Merge "Create AppForegroundHelper"
This commit is contained in:
committed by
Android (Google) Code Review
commit
59f31d5e3c
@@ -23,7 +23,7 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationManagerInternal;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
@@ -32,6 +32,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.location.GpsNetInitiatedHandler;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
/**
|
||||
* This activity is shown to the user for him/her to accept or deny network-initiated
|
||||
@@ -68,14 +69,14 @@ public class NetInitiatedActivity extends AlertActivity implements DialogInterfa
|
||||
private final Handler mHandler = new Handler() {
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case GPS_NO_RESPONSE_TIME_OUT: {
|
||||
if (notificationId != -1) {
|
||||
sendUserResponse(default_response);
|
||||
case GPS_NO_RESPONSE_TIME_OUT: {
|
||||
if (notificationId != -1) {
|
||||
sendUserResponse(default_response);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -137,9 +138,8 @@ public class NetInitiatedActivity extends AlertActivity implements DialogInterfa
|
||||
// Respond to NI Handler under GnssLocationProvider, 1 = accept, 2 = deny
|
||||
private void sendUserResponse(int response) {
|
||||
if (DEBUG) Log.d(TAG, "sendUserResponse, response: " + response);
|
||||
LocationManager locationManager = (LocationManager)
|
||||
this.getSystemService(Context.LOCATION_SERVICE);
|
||||
locationManager.sendNiResponse(notificationId, response);
|
||||
LocationManagerInternal lm = LocalServices.getService(LocationManagerInternal.class);
|
||||
lm.sendNiResponse(notificationId, response);
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
|
||||
@@ -69,8 +69,6 @@ interface ILocationManager
|
||||
double upperRightLatitude, double upperRightLongitude, int maxResults,
|
||||
in GeocoderParams params, out List<Address> addrs);
|
||||
|
||||
boolean sendNiResponse(int notifId, int userResponse);
|
||||
|
||||
boolean addGnssMeasurementsListener(in IGnssMeasurementsListener listener,
|
||||
String packageName, String featureId, String listenerIdentifier);
|
||||
void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections,
|
||||
|
||||
@@ -2397,21 +2397,6 @@ public class LocationManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by NetInitiatedActivity to report user response
|
||||
* for network initiated GPS fix requests.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
public boolean sendNiResponse(int notifId, int userResponse) {
|
||||
try {
|
||||
return mService.sendNiResponse(notifId, userResponse);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPendingIntent(PendingIntent pendingIntent) {
|
||||
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
|
||||
if (!pendingIntent.isTargetedToPackage()) {
|
||||
|
||||
@@ -41,4 +41,19 @@ public abstract class LocationManagerInternal {
|
||||
* @throws IllegalArgumentException if provider is null
|
||||
*/
|
||||
public abstract void requestSetProviderAllowed(@NonNull String provider, boolean allowed);
|
||||
|
||||
/**
|
||||
* Returns true if the given package belongs to a location provider, and so should be afforded
|
||||
* some special privileges.
|
||||
*
|
||||
* @param packageName The package name to check
|
||||
* @return True is the given package belongs to a location provider, false otherwise
|
||||
*/
|
||||
public abstract boolean isProviderPackage(@NonNull String packageName);
|
||||
|
||||
/**
|
||||
* Should only be used by GNSS code.
|
||||
*/
|
||||
// TODO: there is no reason for this to exist as part of any API. move all the logic into gnss
|
||||
public abstract void sendNiResponse(int notifId, int userResponse);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import static android.os.PowerManager.locationPowerSaveModeToString;
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -88,6 +87,7 @@ import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.location.AbstractLocationProvider;
|
||||
import com.android.server.location.AbstractLocationProvider.State;
|
||||
import com.android.server.location.AppForegroundHelper;
|
||||
import com.android.server.location.CallerIdentity;
|
||||
import com.android.server.location.GeocoderProxy;
|
||||
import com.android.server.location.GeofenceManager;
|
||||
@@ -98,12 +98,12 @@ import com.android.server.location.LocationProviderProxy;
|
||||
import com.android.server.location.LocationRequestStatistics;
|
||||
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
|
||||
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
|
||||
import com.android.server.location.LocationSettingsStore;
|
||||
import com.android.server.location.LocationUsageLogger;
|
||||
import com.android.server.location.MockProvider;
|
||||
import com.android.server.location.MockableLocationProvider;
|
||||
import com.android.server.location.PassiveProvider;
|
||||
import com.android.server.location.UserInfoStore;
|
||||
import com.android.server.location.SettingsHelper;
|
||||
import com.android.server.location.UserInfoHelper;
|
||||
import com.android.server.location.gnss.GnssManagerService;
|
||||
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||
|
||||
@@ -140,7 +140,6 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
public Lifecycle(Context context) {
|
||||
super(context);
|
||||
mService = new LocationManagerService(context);
|
||||
LocalServices.addService(LocationManagerInternal.class, mService.new LocalService());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -181,9 +180,6 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
// maximum age of a location before it is no longer considered "current"
|
||||
private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
|
||||
|
||||
private static final int FOREGROUND_IMPORTANCE_CUTOFF
|
||||
= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
|
||||
|
||||
// Location Providers may sometimes deliver location updates
|
||||
// slightly faster that requested - provide grace period so
|
||||
// we don't unnecessarily filter events that are otherwise on
|
||||
@@ -195,21 +191,23 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
private final Object mLock = new Object();
|
||||
private final Context mContext;
|
||||
private final Handler mHandler;
|
||||
private final UserInfoStore mUserInfoStore;
|
||||
private final LocationSettingsStore mSettingsStore;
|
||||
private final LocalService mLocalService;
|
||||
private final UserInfoHelper mUserInfoHelper;
|
||||
private final SettingsHelper mSettingsHelper;
|
||||
private final AppForegroundHelper mAppForegroundHelper;
|
||||
private final LocationUsageLogger mLocationUsageLogger;
|
||||
|
||||
@Nullable private GnssManagerService mGnssManagerService = null;
|
||||
|
||||
private final PassiveLocationProviderManager mPassiveManager;
|
||||
|
||||
private AppOpsManager mAppOps;
|
||||
private PackageManager mPackageManager;
|
||||
private PowerManager mPowerManager;
|
||||
private ActivityManager mActivityManager;
|
||||
|
||||
private GeofenceManager mGeofenceManager;
|
||||
private LocationFudger mLocationFudger;
|
||||
private GeocoderProxy mGeocodeProvider;
|
||||
@Nullable private GnssManagerService mGnssManagerService;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private String mExtraLocationControllerPackage;
|
||||
@@ -245,8 +243,13 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
private LocationManagerService(Context context) {
|
||||
mContext = context;
|
||||
mHandler = FgThread.getHandler();
|
||||
mUserInfoStore = new UserInfoStore(mContext);
|
||||
mSettingsStore = new LocationSettingsStore(mContext, mHandler);
|
||||
mLocalService = new LocalService();
|
||||
|
||||
LocalServices.addService(LocationManagerInternal.class, mLocalService);
|
||||
|
||||
mUserInfoHelper = new UserInfoHelper(mContext);
|
||||
mSettingsHelper = new SettingsHelper(mContext, mHandler);
|
||||
mAppForegroundHelper = new AppForegroundHelper(mContext);
|
||||
mLocationUsageLogger = new LocationUsageLogger();
|
||||
|
||||
// set up passive provider - we do this early because it has no dependencies on system
|
||||
@@ -272,17 +275,23 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
private void onSystemReady() {
|
||||
mUserInfoStore.onSystemReady();
|
||||
mSettingsStore.onSystemReady();
|
||||
mUserInfoHelper.onSystemReady();
|
||||
mSettingsHelper.onSystemReady();
|
||||
mAppForegroundHelper.onSystemReady();
|
||||
|
||||
if (GnssManagerService.isGnssSupported()) {
|
||||
mGnssManagerService = new GnssManagerService(mContext, mSettingsHelper,
|
||||
mAppForegroundHelper, mLocationUsageLogger);
|
||||
mGnssManagerService.onSystemReady();
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
mAppOps = mContext.getSystemService(AppOpsManager.class);
|
||||
mPowerManager = mContext.getSystemService(PowerManager.class);
|
||||
mActivityManager = mContext.getSystemService(ActivityManager.class);
|
||||
|
||||
mLocationFudger = new LocationFudger(mContext, mHandler);
|
||||
mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
|
||||
mGeofenceManager = new GeofenceManager(mContext, mSettingsHelper);
|
||||
|
||||
PowerManagerInternal localPowerManager =
|
||||
LocalServices.getService(PowerManagerInternal.class);
|
||||
@@ -313,17 +322,6 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
});
|
||||
});
|
||||
mActivityManager.addOnUidImportanceListener(
|
||||
(uid, importance) -> {
|
||||
// listener invoked on ui thread, move to our thread to reduce risk of
|
||||
// blocking ui thread
|
||||
mHandler.post(() -> {
|
||||
synchronized (mLock) {
|
||||
onUidImportanceChangedLocked(uid, importance);
|
||||
}
|
||||
});
|
||||
},
|
||||
FOREGROUND_IMPORTANCE_CUTOFF);
|
||||
|
||||
localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
|
||||
state -> {
|
||||
@@ -337,26 +335,13 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
});
|
||||
mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
|
||||
|
||||
mSettingsStore.addOnLocationEnabledChangedListener((userId) -> {
|
||||
synchronized (mLock) {
|
||||
onLocationModeChangedLocked(userId);
|
||||
}
|
||||
});
|
||||
mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
|
||||
synchronized (mLock) {
|
||||
onBackgroundThrottleIntervalChangedLocked();
|
||||
}
|
||||
});
|
||||
mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
|
||||
synchronized (mLock) {
|
||||
onBackgroundThrottleWhitelistChangedLocked();
|
||||
}
|
||||
});
|
||||
mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
|
||||
synchronized (mLock) {
|
||||
onIgnoreSettingsWhitelistChangedLocked();
|
||||
}
|
||||
});
|
||||
mSettingsHelper.addOnLocationEnabledChangedListener(this::onLocationModeChanged);
|
||||
mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
|
||||
this::onBackgroundThrottleIntervalChanged);
|
||||
mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
|
||||
this::onBackgroundThrottleWhitelistChanged);
|
||||
mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
|
||||
this::onIgnoreSettingsWhitelistChanged);
|
||||
|
||||
new PackageMonitor() {
|
||||
@Override
|
||||
@@ -367,11 +352,9 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
}.register(mContext, mHandler.getLooper(), true);
|
||||
|
||||
mUserInfoStore.addListener((oldUserId, newUserId) -> {
|
||||
synchronized (mLock) {
|
||||
onUserChangedLocked(oldUserId, newUserId);
|
||||
}
|
||||
});
|
||||
mUserInfoHelper.addListener(this::onUserChanged);
|
||||
|
||||
mAppForegroundHelper.addListener(this::onAppForegroundChanged);
|
||||
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
@@ -398,7 +381,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
// switching the user from null to current here performs the bulk of the initialization
|
||||
// work. the user being changed will cause a reload of all user specific settings, which
|
||||
// causes initialization, and propagates changes until a steady state is reached
|
||||
onUserChangedLocked(UserHandle.USER_NULL, mUserInfoStore.getCurrentUserId());
|
||||
onUserChanged(UserHandle.USER_NULL, mUserInfoHelper.getCurrentUserId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,20 +438,23 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onLocationModeChangedLocked(int userId) {
|
||||
private void onLocationModeChanged(int userId) {
|
||||
boolean enabled = mSettingsHelper.isLocationEnabled(userId);
|
||||
|
||||
if (D) {
|
||||
Log.d(TAG, "[u" + userId + "] location enabled = " + isLocationEnabledForUser(userId));
|
||||
Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
|
||||
}
|
||||
|
||||
Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
|
||||
.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId))
|
||||
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
|
||||
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
|
||||
synchronized (mLock) {
|
||||
Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
|
||||
.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, enabled)
|
||||
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
|
||||
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
|
||||
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
manager.onEnabledChangedLocked(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,58 +479,55 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onUidImportanceChangedLocked(int uid, int importance) {
|
||||
boolean foreground = LocationManagerServiceUtils.isImportanceForeground(importance);
|
||||
HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
|
||||
for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
|
||||
String provider = entry.getKey();
|
||||
for (UpdateRecord record : entry.getValue()) {
|
||||
if (record.mReceiver.mCallerIdentity.mUid == uid
|
||||
&& record.mIsForegroundUid != foreground) {
|
||||
if (D) {
|
||||
Log.d(TAG, "request from uid " + uid + " is now "
|
||||
+ LocationManagerServiceUtils.foregroundAsString(
|
||||
foreground));
|
||||
}
|
||||
record.updateForeground(foreground);
|
||||
private void onAppForegroundChanged(int uid, boolean foreground) {
|
||||
synchronized (mLock) {
|
||||
HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
|
||||
for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
|
||||
String provider = entry.getKey();
|
||||
for (UpdateRecord record : entry.getValue()) {
|
||||
if (record.mReceiver.mCallerIdentity.mUid == uid
|
||||
&& record.mIsForegroundUid != foreground) {
|
||||
record.updateForeground(foreground);
|
||||
|
||||
if (!isThrottlingExemptLocked(record.mReceiver.mCallerIdentity)) {
|
||||
affectedProviders.add(provider);
|
||||
if (!isThrottlingExempt(record.mReceiver.mCallerIdentity)) {
|
||||
affectedProviders.add(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String provider : affectedProviders) {
|
||||
applyRequirementsLocked(provider);
|
||||
for (String provider : affectedProviders) {
|
||||
applyRequirementsLocked(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onBackgroundThrottleIntervalChangedLocked() {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
applyRequirementsLocked(manager);
|
||||
private void onBackgroundThrottleIntervalChanged() {
|
||||
synchronized (mLock) {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
applyRequirementsLocked(manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onBackgroundThrottleWhitelistChangedLocked() {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
applyRequirementsLocked(manager);
|
||||
private void onBackgroundThrottleWhitelistChanged() {
|
||||
synchronized (mLock) {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
applyRequirementsLocked(manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("lock")
|
||||
private void onIgnoreSettingsWhitelistChangedLocked() {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
applyRequirementsLocked(manager);
|
||||
private void onIgnoreSettingsWhitelistChanged() {
|
||||
synchronized (mLock) {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
applyRequirementsLocked(manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void initializeProvidersLocked() {
|
||||
if (GnssManagerService.isGnssSupported()) {
|
||||
mGnssManagerService = new GnssManagerService(this, mContext, mLocationUsageLogger);
|
||||
if (mGnssManagerService != null) {
|
||||
LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER);
|
||||
mProviderManagers.add(gnssManager);
|
||||
gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
|
||||
@@ -627,19 +610,20 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onUserChangedLocked(int oldUserId, int newUserId) {
|
||||
private void onUserChanged(int oldUserId, int newUserId) {
|
||||
if (D) {
|
||||
Log.d(TAG, "foreground user is changing to " + newUserId);
|
||||
}
|
||||
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
|
||||
mSettingsStore.setLocationProviderAllowed(manager.getName(),
|
||||
manager.isEnabled(newUserId), newUserId);
|
||||
synchronized (mLock) {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
|
||||
mSettingsHelper.setLocationProviderAllowed(manager.getName(),
|
||||
manager.isEnabled(newUserId), newUserId);
|
||||
|
||||
manager.onEnabledChangedLocked(oldUserId);
|
||||
manager.onEnabledChangedLocked(newUserId);
|
||||
manager.onEnabledChangedLocked(oldUserId);
|
||||
manager.onEnabledChangedLocked(newUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,7 +762,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
// it would be more correct to call this for all users, but we know this can
|
||||
// only affect the current user since providers are disabled for non-current
|
||||
// users
|
||||
onEnabledChangedLocked(mUserInfoStore.getCurrentUserId());
|
||||
onEnabledChangedLocked(mUserInfoHelper.getCurrentUserId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,14 +771,14 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return isEnabled(mUserInfoStore.getCurrentUserId());
|
||||
return isEnabled(mUserInfoHelper.getCurrentUserId());
|
||||
}
|
||||
|
||||
public boolean isEnabled(int userId) {
|
||||
synchronized (mLock) {
|
||||
// normalize user id to always refer to parent since profile state is always the
|
||||
// same as parent state
|
||||
userId = mUserInfoStore.getParentUserId(userId);
|
||||
userId = mUserInfoHelper.getParentUserId(userId);
|
||||
return mEnabled.get(userId, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
@@ -808,13 +792,13 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
// normalize user id to always refer to parent since profile state is always the same
|
||||
// as parent state
|
||||
userId = mUserInfoStore.getParentUserId(userId);
|
||||
userId = mUserInfoHelper.getParentUserId(userId);
|
||||
|
||||
// if any property that contributes to "enabled" here changes state, it MUST result
|
||||
// in a direct or indrect call to onEnabledChangedLocked. this allows the provider to
|
||||
// guarantee that it will always eventually reach the correct state.
|
||||
boolean enabled = (userId == mUserInfoStore.getCurrentUserId())
|
||||
&& mSettingsStore.isLocationEnabled(userId) && mProvider.getState().allowed;
|
||||
boolean enabled = (userId == mUserInfoHelper.getCurrentUserId())
|
||||
&& mSettingsHelper.isLocationEnabled(userId) && mProvider.getState().allowed;
|
||||
|
||||
if (enabled == isEnabled(userId)) {
|
||||
return;
|
||||
@@ -829,7 +813,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
// fused and passive provider never get public updates for legacy reasons
|
||||
if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
|
||||
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
|
||||
mSettingsStore.setLocationProviderAllowed(mName, enabled, userId);
|
||||
mSettingsHelper.setLocationProviderAllowed(mName, enabled, userId);
|
||||
|
||||
Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
|
||||
.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
|
||||
@@ -1009,7 +993,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
if (manager == null) {
|
||||
continue;
|
||||
}
|
||||
if (!manager.isEnabled() && !isSettingsExemptLocked(updateRecord)) {
|
||||
if (!manager.isEnabled() && !isSettingsExempt(updateRecord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1475,13 +1459,13 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
|
||||
if (records != null) {
|
||||
for (UpdateRecord record : records) {
|
||||
if (!mUserInfoStore.isCurrentUserOrProfile(
|
||||
if (!mUserInfoHelper.isCurrentUserOrProfile(
|
||||
UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// requests that ignore location settings will never provide notifications
|
||||
if (isSettingsExemptLocked(record)) {
|
||||
if (isSettingsExempt(record)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1520,14 +1504,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
// if provider is not active, it should not respond to requests
|
||||
|
||||
if (mProviderManagers.contains(manager) && records != null && !records.isEmpty()) {
|
||||
long backgroundThrottleInterval;
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
backgroundThrottleInterval = mSettingsStore.getBackgroundThrottleIntervalMs();
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
long backgroundThrottleInterval = mSettingsHelper.getBackgroundThrottleIntervalMs();
|
||||
|
||||
ArrayList<LocationRequest> requests = new ArrayList<>(records.size());
|
||||
|
||||
@@ -1540,7 +1517,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
// initialize the low power mode to true and set to false if any of the records requires
|
||||
providerRequest.setLowPowerMode(true);
|
||||
for (UpdateRecord record : records) {
|
||||
if (!mUserInfoStore.isCurrentUserOrProfile(
|
||||
if (!mUserInfoHelper.isCurrentUserOrProfile(
|
||||
UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
|
||||
continue;
|
||||
}
|
||||
@@ -1554,7 +1531,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
final boolean isBatterySaverDisablingLocation = shouldThrottleRequests
|
||||
|| (isForegroundOnlyMode && !record.mIsForegroundUid);
|
||||
if (!manager.isEnabled() || isBatterySaverDisablingLocation) {
|
||||
if (isSettingsExemptLocked(record)) {
|
||||
if (isSettingsExempt(record)) {
|
||||
providerRequest.setLocationSettingsIgnored(true);
|
||||
providerRequest.setLowPowerMode(false);
|
||||
} else {
|
||||
@@ -1567,7 +1544,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
|
||||
// if we're forcing location, don't apply any throttling
|
||||
if (!providerRequest.isLocationSettingsIgnored() && !isThrottlingExemptLocked(
|
||||
if (!providerRequest.isLocationSettingsIgnored() && !isThrottlingExempt(
|
||||
record.mReceiver.mCallerIdentity)) {
|
||||
if (!record.mIsForegroundUid) {
|
||||
interval = Math.max(interval, backgroundThrottleInterval);
|
||||
@@ -1599,7 +1576,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
// TODO: overflow
|
||||
long thresholdInterval = (providerRequest.getInterval() + 1000) * 3 / 2;
|
||||
for (UpdateRecord record : records) {
|
||||
if (mUserInfoStore.isCurrentUserOrProfile(
|
||||
if (mUserInfoHelper.isCurrentUserOrProfile(
|
||||
UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
|
||||
LocationRequest locationRequest = record.mRequest;
|
||||
|
||||
@@ -1648,41 +1625,39 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
@Override
|
||||
public String[] getBackgroundThrottlingWhitelist() {
|
||||
return mSettingsStore.getBackgroundThrottlePackageWhitelist().toArray(new String[0]);
|
||||
return mSettingsHelper.getBackgroundThrottlePackageWhitelist().toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getIgnoreSettingsWhitelist() {
|
||||
return mSettingsStore.getIgnoreSettingsPackageWhitelist().toArray(new String[0]);
|
||||
return mSettingsHelper.getIgnoreSettingsPackageWhitelist().toArray(new String[0]);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
public boolean isThrottlingExemptLocked(CallerIdentity callerIdentity) {
|
||||
private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
|
||||
if (callerIdentity.mUid == Process.SYSTEM_UID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mSettingsStore.getBackgroundThrottlePackageWhitelist().contains(
|
||||
if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
|
||||
callerIdentity.mPackageName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isProviderPackage(callerIdentity.mPackageName);
|
||||
return mLocalService.isProviderPackage(callerIdentity.mPackageName);
|
||||
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean isSettingsExemptLocked(UpdateRecord record) {
|
||||
private boolean isSettingsExempt(UpdateRecord record) {
|
||||
if (!record.mRealRequest.isLocationSettingsIgnored()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSettingsStore.getIgnoreSettingsPackageWhitelist().contains(
|
||||
if (mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
|
||||
record.mReceiver.mCallerIdentity.mPackageName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName);
|
||||
return mLocalService.isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName);
|
||||
|
||||
}
|
||||
|
||||
@@ -1705,10 +1680,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
mRealRequest = request;
|
||||
mRequest = request;
|
||||
mReceiver = receiver;
|
||||
mIsForegroundUid =
|
||||
LocationManagerServiceUtils.isImportanceForeground(
|
||||
mActivityManager.getPackageImportance(
|
||||
mReceiver.mCallerIdentity.mPackageName));
|
||||
mIsForegroundUid = mAppForegroundHelper.isAppForeground(mReceiver.mCallerIdentity.mUid);
|
||||
|
||||
if (D && receiver.mCallerIdentity.mPid == Process.myPid()) {
|
||||
mStackTrace = new Throwable();
|
||||
@@ -1753,7 +1725,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
mReceiver.isListener(),
|
||||
mReceiver.isPendingIntent(),
|
||||
/* geofence= */ null,
|
||||
mActivityManager.getPackageImportance(packageName));
|
||||
mAppForegroundHelper.getImportance(mReceiver.mCallerIdentity.mUid));
|
||||
|
||||
// remove from mRecordsByProvider
|
||||
ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
|
||||
@@ -1923,7 +1895,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
|
||||
packageName, request, listener != null, intent != null,
|
||||
/* geofence= */ null,
|
||||
mActivityManager.getPackageImportance(packageName));
|
||||
mAppForegroundHelper.getImportance(uid));
|
||||
|
||||
Receiver receiver;
|
||||
if (intent != null) {
|
||||
@@ -1961,7 +1933,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
|
||||
+ " " + name + " " + request + " from " + packageName + "(" + uid + " "
|
||||
+ (record.mIsForegroundUid ? "foreground" : "background")
|
||||
+ (isThrottlingExemptLocked(receiver.mCallerIdentity)
|
||||
+ (isThrottlingExempt(receiver.mCallerIdentity)
|
||||
? " [whitelisted]" : "") + ")");
|
||||
}
|
||||
|
||||
@@ -1970,7 +1942,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
oldRecord.disposeLocked(false);
|
||||
}
|
||||
|
||||
if (!manager.isEnabled() && !isSettingsExemptLocked(record)) {
|
||||
if (!manager.isEnabled() && !isSettingsExempt(record)) {
|
||||
// Notify the listener that updates are currently disabled - but only if the request
|
||||
// does not ignore location settings
|
||||
receiver.callProviderEnabledLocked(name, false);
|
||||
@@ -2060,7 +2032,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
final int uid = Binder.getCallingUid();
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (mSettingsStore.isLocationPackageBlacklisted(UserHandle.getUserId(uid),
|
||||
if (mSettingsHelper.isLocationPackageBlacklisted(UserHandle.getUserId(uid),
|
||||
packageName)) {
|
||||
if (D) {
|
||||
Log.d(TAG, "not returning last loc for blacklisted app: "
|
||||
@@ -2077,8 +2049,8 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
if (manager == null) return null;
|
||||
|
||||
// only the current user or location providers may get location this way
|
||||
if (!mUserInfoStore.isCurrentUserOrProfile(UserHandle.getUserId(uid))
|
||||
&& !isProviderPackage(packageName)) {
|
||||
if (!mUserInfoHelper.isCurrentUserOrProfile(UserHandle.getUserId(uid))
|
||||
&& !mLocalService.isProviderPackage(packageName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2102,7 +2074,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
String op = resolutionLevelToOpStr(allowedResolutionLevel);
|
||||
long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
|
||||
SystemClock.elapsedRealtime() - location.getElapsedRealtimeNanos());
|
||||
if (locationAgeMs > mSettingsStore.getMaxLastLocationAgeMs()
|
||||
if (locationAgeMs > mSettingsHelper.getMaxLastLocationAgeMs()
|
||||
&& (mAppOps.unsafeCheckOp(op, uid, packageName)
|
||||
== AppOpsManager.MODE_FOREGROUND)) {
|
||||
return null;
|
||||
@@ -2145,29 +2117,21 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
|
||||
SystemClock.elapsedRealtimeNanos() - lastLocation.getElapsedRealtimeNanos());
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
|
||||
try {
|
||||
listener.onLocationChanged(lastLocation);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
|
||||
try {
|
||||
listener.onLocationChanged(lastLocation);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// packageName already validated by getLastLocation() call above
|
||||
boolean foreground = LocationManagerServiceUtils.isImportanceForeground(
|
||||
mActivityManager.getPackageImportance(packageName));
|
||||
if (!foreground) {
|
||||
if (locationAgeMs < mSettingsStore.getBackgroundThrottleIntervalMs()) {
|
||||
// not allowed to request new locations, so we can't return anything
|
||||
return false;
|
||||
}
|
||||
if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())) {
|
||||
if (locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
|
||||
// not allowed to request new locations, so we can't return anything
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2252,20 +2216,19 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
Log.w(TAG, "proximity alerts are currently available only to the primary user");
|
||||
return;
|
||||
}
|
||||
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_STARTED,
|
||||
LocationStatsEnums.API_REQUEST_GEOFENCE,
|
||||
packageName,
|
||||
request,
|
||||
/* hasListener= */ false,
|
||||
true,
|
||||
geofence,
|
||||
mAppForegroundHelper.getImportance(uid));
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_STARTED,
|
||||
LocationStatsEnums.API_REQUEST_GEOFENCE,
|
||||
packageName,
|
||||
request,
|
||||
/* hasListener= */ false,
|
||||
true,
|
||||
geofence,
|
||||
mActivityManager.getPackageImportance(packageName));
|
||||
}
|
||||
|
||||
mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
|
||||
uid, packageName, featureId, listenerIdentifier);
|
||||
} finally {
|
||||
@@ -2282,20 +2245,19 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
|
||||
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_ENDED,
|
||||
LocationStatsEnums.API_REQUEST_GEOFENCE,
|
||||
packageName,
|
||||
/* LocationRequest= */ null,
|
||||
/* hasListener= */ false,
|
||||
true,
|
||||
geofence,
|
||||
mAppForegroundHelper.getImportance(Binder.getCallingUid()));
|
||||
|
||||
// geo-fence manager uses the public location API, need to clear identity
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_ENDED,
|
||||
LocationStatsEnums.API_REQUEST_GEOFENCE,
|
||||
packageName,
|
||||
/* LocationRequest= */ null,
|
||||
/* hasListener= */ false,
|
||||
true,
|
||||
geofence,
|
||||
mActivityManager.getPackageImportance(packageName));
|
||||
}
|
||||
mGeofenceManager.removeFence(geofence, intent);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
@@ -2391,12 +2353,6 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendNiResponse(int notifId, int userResponse) {
|
||||
return mGnssManagerService != null && mGnssManagerService.sendNiResponse(notifId,
|
||||
userResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderProperties getProviderProperties(String providerName) {
|
||||
LocationProviderManager manager = getLocationProviderManager(providerName);
|
||||
@@ -2408,20 +2364,13 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
@Override
|
||||
public boolean isProviderPackage(String packageName) {
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
|
||||
Manifest.permission.READ_DEVICE_CONFIG + " permission required");
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
if (manager.getPackages().contains(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null);
|
||||
return mLocalService.isProviderPackage(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getProviderPackages(String providerName) {
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
|
||||
Manifest.permission.READ_DEVICE_CONFIG + " permission required");
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null);
|
||||
LocationProviderManager manager = getLocationProviderManager(providerName);
|
||||
return manager == null ? Collections.emptyList() : new ArrayList<>(manager.getPackages());
|
||||
}
|
||||
@@ -2461,28 +2410,19 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
@Override
|
||||
public boolean isLocationEnabledForUser(int userId) {
|
||||
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
|
||||
if (UserHandle.getCallingUserId() != userId) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS,
|
||||
"Requires INTERACT_ACROSS_USERS permission");
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
|
||||
null);
|
||||
}
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mSettingsStore.isLocationEnabled(userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
return mSettingsHelper.isLocationEnabled(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProviderEnabledForUser(String providerName, int userId) {
|
||||
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
|
||||
if (UserHandle.getCallingUserId() != userId) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS,
|
||||
"Requires INTERACT_ACROSS_USERS permission");
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
|
||||
null);
|
||||
}
|
||||
|
||||
// Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
|
||||
@@ -2593,12 +2533,12 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
Receiver receiver = r.mReceiver;
|
||||
boolean receiverDead = false;
|
||||
|
||||
if (!manager.isEnabled() && !isSettingsExemptLocked(r)) {
|
||||
if (!manager.isEnabled() && !isSettingsExempt(r)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int receiverUserId = UserHandle.getUserId(receiver.mCallerIdentity.mUid);
|
||||
if (!mUserInfoStore.isCurrentUserOrProfile(receiverUserId)
|
||||
if (!mUserInfoHelper.isCurrentUserOrProfile(receiverUserId)
|
||||
&& !isProviderPackage(receiver.mCallerIdentity.mPackageName)) {
|
||||
if (D) {
|
||||
Log.d(TAG, "skipping loc update for background user " + receiverUserId +
|
||||
@@ -2607,7 +2547,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mSettingsStore.isLocationPackageBlacklisted(receiverUserId,
|
||||
if (mSettingsHelper.isLocationPackageBlacklisted(receiverUserId,
|
||||
receiver.mCallerIdentity.mPackageName)) {
|
||||
if (D) {
|
||||
Log.d(TAG, "skipping loc update for blacklisted app: " +
|
||||
@@ -2855,12 +2795,12 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
ipw.println("User Info:");
|
||||
ipw.increaseIndent();
|
||||
mUserInfoStore.dump(fd, ipw, args);
|
||||
mUserInfoHelper.dump(fd, ipw, args);
|
||||
ipw.decreaseIndent();
|
||||
|
||||
ipw.println("Location Settings:");
|
||||
ipw.increaseIndent();
|
||||
mSettingsStore.dump(fd, ipw, args);
|
||||
mSettingsHelper.dump(fd, ipw, args);
|
||||
ipw.decreaseIndent();
|
||||
|
||||
ipw.println("Battery Saver Location Mode: "
|
||||
@@ -2960,5 +2900,22 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProviderPackage(String packageName) {
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
if (manager.getPackages().contains(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendNiResponse(int notifId, int userResponse) {
|
||||
if (mGnssManagerService != null) {
|
||||
mGnssManagerService.sendNiResponse(notifId, userResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
package com.android.server;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
@@ -91,12 +89,8 @@ public class LocationManagerServiceUtils {
|
||||
|
||||
/**
|
||||
* Link listener (i.e. callback) to a binder, so that it will be called upon binder's death.
|
||||
*
|
||||
* @param binder that calls listener upon death
|
||||
* @return true if listener is successfully linked to binder, false otherwise
|
||||
*/
|
||||
public boolean linkToListenerDeathNotificationLocked(
|
||||
IBinder binder) {
|
||||
public boolean linkToListenerDeathNotificationLocked(IBinder binder) {
|
||||
try {
|
||||
binder.linkToDeath(this, 0 /* flags */);
|
||||
return true;
|
||||
@@ -110,54 +104,13 @@ public class LocationManagerServiceUtils {
|
||||
|
||||
/**
|
||||
* Unlink death listener (i.e. callback) from binder.
|
||||
*
|
||||
* @param binder that calls listener upon death
|
||||
* @return true if binder is successfully unlinked from binder, false otherwise
|
||||
*/
|
||||
public boolean unlinkFromListenerDeathNotificationLocked(
|
||||
IBinder binder) {
|
||||
public void unlinkFromListenerDeathNotificationLocked(IBinder binder) {
|
||||
try {
|
||||
binder.unlinkToDeath(this, 0 /* flags */);
|
||||
return true;
|
||||
} catch (NoSuchElementException e) {
|
||||
// if the death callback isn't connected (it should be...), log error,
|
||||
// swallow the exception and return
|
||||
Log.w(TAG, "Could not unlink " + mListenerName + " death callback.", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert boolean foreground into "foreground" or "background" string.
|
||||
*
|
||||
* @param foreground boolean indicating foreground
|
||||
* @return "foreground" string if true, false otherwise
|
||||
*/
|
||||
public static String foregroundAsString(boolean foreground) {
|
||||
return foreground ? "foreground" : "background";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Classifies importance level as foreground or not.
|
||||
*
|
||||
* @param importance level as int
|
||||
* @return boolean indicating if importance level is foreground or greater
|
||||
*/
|
||||
public static boolean isImportanceForeground(int importance) {
|
||||
return importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package importance level.
|
||||
*
|
||||
* @param packageName package name
|
||||
* @return package importance level as int
|
||||
*/
|
||||
public static int getPackageImportance(String packageName, Context context) {
|
||||
return ((ActivityManager) context.getSystemService(
|
||||
Context.ACTIVITY_SERVICE)).getPackageImportance(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
@@ -120,7 +121,8 @@ public abstract class AbstractLocationProvider {
|
||||
if (providerPackageNames.equals(this.providerPackageNames)) {
|
||||
return this;
|
||||
} else {
|
||||
return new State(allowed, properties, providerPackageNames);
|
||||
return new State(allowed, properties,
|
||||
Collections.unmodifiableSet(new ArraySet<>(providerPackageNames)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
|
||||
import static android.app.ActivityManager.RunningAppProcessInfo.Importance;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.FgThread;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* Provides accessors and listeners for all application foreground status. An application is
|
||||
* considered foreground if it's uid's importance level is at or more important than
|
||||
* {@link android.app.ActivityManager.RunningAppProcessInfo#IMPORTANCE_FOREGROUND_SERVICE}.
|
||||
*/
|
||||
public class AppForegroundHelper {
|
||||
|
||||
/**
|
||||
* Listener for application foreground state changes.
|
||||
*/
|
||||
public interface AppForegroundListener {
|
||||
/**
|
||||
* Called when an application's foreground state changes.
|
||||
*/
|
||||
void onAppForegroundChanged(int uid, boolean foreground);
|
||||
}
|
||||
|
||||
// importance constants decrement with increasing importance - this is our limit for an
|
||||
// importance level we consider foreground.
|
||||
private static final int FOREGROUND_IMPORTANCE_CUTOFF = IMPORTANCE_FOREGROUND_SERVICE;
|
||||
|
||||
private static boolean isForeground(@Importance int importance) {
|
||||
return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
private final CopyOnWriteArrayList<AppForegroundListener> mListeners;
|
||||
|
||||
@GuardedBy("this")
|
||||
@Nullable private ActivityManager mActivityManager;
|
||||
|
||||
public AppForegroundHelper(Context context) {
|
||||
mContext = context;
|
||||
mListeners = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
||||
/** Called when system is ready. */
|
||||
public synchronized void onSystemReady() {
|
||||
if (mActivityManager != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mActivityManager = Objects.requireNonNull(mContext.getSystemService(ActivityManager.class));
|
||||
mActivityManager.addOnUidImportanceListener(this::onAppForegroundChanged,
|
||||
FOREGROUND_IMPORTANCE_CUTOFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for app foreground changed events. Callbacks occur on an unspecified thread.
|
||||
*/
|
||||
public void addListener(AppForegroundListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener for app foreground changed events.
|
||||
*/
|
||||
public void removeListener(AppForegroundListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
private void onAppForegroundChanged(int uid, @Importance int importance) {
|
||||
// invoked on ui thread, move to fg thread so we don't block the ui thread
|
||||
boolean foreground = isForeground(importance);
|
||||
FgThread.getHandler().post(() -> {
|
||||
for (AppForegroundListener listener : mListeners) {
|
||||
listener.onAppForegroundChanged(uid, foreground);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the given uid is currently foreground.
|
||||
*/
|
||||
public boolean isAppForeground(int uid) {
|
||||
return isForeground(getImportance(uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current importance of the given uid.
|
||||
*
|
||||
* @deprecated Prefer {@link #isAppForeground(int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Importance
|
||||
public int getImportance(int uid) {
|
||||
synchronized (this) {
|
||||
Preconditions.checkState(mActivityManager != null);
|
||||
}
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mActivityManager.getUidImportance(uid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
|
||||
private final AppOpsManager mAppOps;
|
||||
private final PowerManager.WakeLock mWakeLock;
|
||||
|
||||
private final LocationSettingsStore mSettingsStore;
|
||||
private final SettingsHelper mSettingsStore;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
@@ -111,7 +111,7 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
|
||||
*/
|
||||
private boolean mPendingUpdate;
|
||||
|
||||
public GeofenceManager(Context context, LocationSettingsStore settingsStore) {
|
||||
public GeofenceManager(Context context, SettingsHelper settingsStore) {
|
||||
mContext = context;
|
||||
mHandler = new GeofenceHandler(FgThread.getHandler().getLooper());
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ import android.os.BatteryStats;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.PersistableBundle;
|
||||
@@ -76,6 +75,7 @@ import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
import com.android.internal.location.gnssmetrics.GnssMetrics;
|
||||
import com.android.server.DeviceIdleInternal;
|
||||
import com.android.server.FgThread;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
|
||||
import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
|
||||
@@ -624,12 +624,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
|
||||
}
|
||||
}
|
||||
|
||||
public GnssLocationProvider(Context context, Handler handler) {
|
||||
super(context, new HandlerExecutor(handler));
|
||||
public GnssLocationProvider(Context context) {
|
||||
super(context, FgThread.getExecutor());
|
||||
|
||||
ensureInitialized();
|
||||
|
||||
mLooper = handler.getLooper();
|
||||
mLooper = FgThread.getHandler().getLooper();
|
||||
|
||||
// Create a wake lock
|
||||
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||
|
||||
@@ -54,7 +54,7 @@ import java.util.function.Supplier;
|
||||
/**
|
||||
* Provides accessors and listeners for all location related settings.
|
||||
*/
|
||||
public class LocationSettingsStore {
|
||||
public class SettingsHelper {
|
||||
|
||||
/**
|
||||
* Listener for user-specific settings changes.
|
||||
@@ -99,7 +99,7 @@ public class LocationSettingsStore {
|
||||
private final StringSetCachedGlobalSetting mIgnoreSettingsPackageWhitelist;
|
||||
|
||||
// TODO: get rid of handler
|
||||
public LocationSettingsStore(Context context, Handler handler) {
|
||||
public SettingsHelper(Context context, Handler handler) {
|
||||
mContext = context;
|
||||
|
||||
mLocationMode = new IntegerSecureSetting(context, LOCATION_MODE, handler);
|
||||
@@ -118,7 +118,7 @@ public class LocationSettingsStore {
|
||||
}
|
||||
|
||||
/** Called when system is ready. */
|
||||
public synchronized void onSystemReady() {
|
||||
public void onSystemReady() {
|
||||
mLocationMode.register();
|
||||
mBackgroundThrottleIntervalMs.register();
|
||||
mLocationPackageBlacklist.register();
|
||||
@@ -135,7 +135,8 @@ public class LocationSettingsStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the location enabled setting.
|
||||
* Add a listener for changes to the location enabled setting. Callbacks occur on an unspecified
|
||||
* thread.
|
||||
*/
|
||||
public void addOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
|
||||
mLocationMode.addListener(listener);
|
||||
@@ -156,7 +157,8 @@ public class LocationSettingsStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the background throttle interval.
|
||||
* Add a listener for changes to the background throttle interval. Callbacks occur on an
|
||||
* unspecified thread.
|
||||
*/
|
||||
public void addOnBackgroundThrottleIntervalChangedListener(
|
||||
GlobalSettingChangedListener listener) {
|
||||
@@ -204,7 +206,8 @@ public class LocationSettingsStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the background throttle package whitelist.
|
||||
* Add a listener for changes to the background throttle package whitelist. Callbacks occur on
|
||||
* an unspecified thread.
|
||||
*/
|
||||
public void addOnBackgroundThrottlePackageWhitelistChangedListener(
|
||||
GlobalSettingChangedListener listener) {
|
||||
@@ -227,7 +230,8 @@ public class LocationSettingsStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the ignore settings package whitelist.
|
||||
* Add a listener for changes to the ignore settings package whitelist. Callbacks occur on an
|
||||
* unspecified thread.
|
||||
*/
|
||||
public void addOnIgnoreSettingsPackageWhitelistChangedListener(
|
||||
GlobalSettingChangedListener listener) {
|
||||
@@ -340,6 +344,8 @@ public class LocationSettingsStore {
|
||||
private abstract static class ObservingSetting extends ContentObserver {
|
||||
|
||||
private final CopyOnWriteArrayList<UserSettingChangedListener> mListeners;
|
||||
|
||||
@GuardedBy("this")
|
||||
private boolean mRegistered;
|
||||
|
||||
private ObservingSetting(Handler handler) {
|
||||
@@ -347,11 +353,11 @@ public class LocationSettingsStore {
|
||||
mListeners = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
||||
protected boolean isRegistered() {
|
||||
protected synchronized boolean isRegistered() {
|
||||
return mRegistered;
|
||||
}
|
||||
|
||||
protected void register(Context context, Uri uri) {
|
||||
protected synchronized void register(Context context, Uri uri) {
|
||||
if (mRegistered) {
|
||||
return;
|
||||
}
|
||||
@@ -393,8 +399,13 @@ public class LocationSettingsStore {
|
||||
}
|
||||
|
||||
public int getValueForUser(int defaultValue, int userId) {
|
||||
return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName,
|
||||
defaultValue, userId);
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName,
|
||||
defaultValue, userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +428,7 @@ public class LocationSettingsStore {
|
||||
mCachedUserId = UserHandle.USER_NULL;
|
||||
}
|
||||
|
||||
public synchronized void register() {
|
||||
public void register() {
|
||||
register(mContext, Settings.Secure.getUriFor(mSettingName));
|
||||
}
|
||||
|
||||
@@ -426,12 +437,17 @@ public class LocationSettingsStore {
|
||||
|
||||
List<String> value = mCachedValue;
|
||||
if (userId != mCachedUserId) {
|
||||
String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
|
||||
mSettingName, userId);
|
||||
if (TextUtils.isEmpty(setting)) {
|
||||
value = Collections.emptyList();
|
||||
} else {
|
||||
value = Arrays.asList(setting.split(","));
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
|
||||
mSettingName, userId);
|
||||
if (TextUtils.isEmpty(setting)) {
|
||||
value = Collections.emptyList();
|
||||
} else {
|
||||
value = Arrays.asList(setting.split(","));
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
|
||||
if (isRegistered()) {
|
||||
@@ -473,8 +489,13 @@ public class LocationSettingsStore {
|
||||
}
|
||||
|
||||
public long getValue(long defaultValue) {
|
||||
return Settings.Global.getLong(mContext.getContentResolver(), mSettingName,
|
||||
defaultValue);
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return Settings.Global.getLong(mContext.getContentResolver(), mSettingName,
|
||||
defaultValue);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,18 +520,23 @@ public class LocationSettingsStore {
|
||||
mValid = false;
|
||||
}
|
||||
|
||||
public synchronized void register() {
|
||||
public void register() {
|
||||
register(mContext, Settings.Global.getUriFor(mSettingName));
|
||||
}
|
||||
|
||||
public synchronized Set<String> getValue() {
|
||||
ArraySet<String> value = mCachedValue;
|
||||
if (!mValid) {
|
||||
value = new ArraySet<>(mBaseValuesSupplier.get());
|
||||
String setting = Settings.Global.getString(mContext.getContentResolver(),
|
||||
mSettingName);
|
||||
if (!TextUtils.isEmpty(setting)) {
|
||||
value.addAll(Arrays.asList(setting.split(",")));
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
value = new ArraySet<>(mBaseValuesSupplier.get());
|
||||
String setting = Settings.Global.getString(mContext.getContentResolver(),
|
||||
mSettingName);
|
||||
if (!TextUtils.isEmpty(setting)) {
|
||||
value.addAll(Arrays.asList(setting.split(",")));
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
|
||||
if (isRegistered()) {
|
||||
@@ -42,7 +42,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
/**
|
||||
* Provides accessors and listeners for all user info.
|
||||
*/
|
||||
public class UserInfoStore {
|
||||
public class UserInfoHelper {
|
||||
|
||||
/**
|
||||
* Listener for current user changes.
|
||||
@@ -58,20 +58,16 @@ public class UserInfoStore {
|
||||
private final CopyOnWriteArrayList<UserChangedListener> mListeners;
|
||||
|
||||
@GuardedBy("this")
|
||||
@Nullable
|
||||
private UserManager mUserManager;
|
||||
@Nullable private UserManager mUserManager;
|
||||
|
||||
@UserIdInt private volatile int mCurrentUserId;
|
||||
|
||||
@GuardedBy("this")
|
||||
@UserIdInt
|
||||
private int mCurrentUserId;
|
||||
|
||||
@GuardedBy("this")
|
||||
@UserIdInt
|
||||
private int mCachedParentUserId;
|
||||
@UserIdInt private int mCachedParentUserId;
|
||||
@GuardedBy("this")
|
||||
private int[] mCachedProfileUserIds;
|
||||
|
||||
public UserInfoStore(Context context) {
|
||||
public UserInfoHelper(Context context) {
|
||||
mContext = context;
|
||||
mListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
@@ -120,7 +116,7 @@ public class UserInfoStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for user changed events.
|
||||
* Adds a listener for user changed events. Callbacks occur on an unspecified thread.
|
||||
*/
|
||||
public void addListener(UserChangedListener listener) {
|
||||
mListeners.add(listener);
|
||||
@@ -134,16 +130,13 @@ public class UserInfoStore {
|
||||
}
|
||||
|
||||
private void onUserChanged(@UserIdInt int newUserId) {
|
||||
int oldUserId;
|
||||
synchronized (this) {
|
||||
if (newUserId == mCurrentUserId) {
|
||||
return;
|
||||
}
|
||||
|
||||
oldUserId = mCurrentUserId;
|
||||
mCurrentUserId = newUserId;
|
||||
if (newUserId == mCurrentUserId) {
|
||||
return;
|
||||
}
|
||||
|
||||
int oldUserId = mCurrentUserId;
|
||||
mCurrentUserId = newUserId;
|
||||
|
||||
for (UserChangedListener listener : mListeners) {
|
||||
listener.onUserChanged(oldUserId, newUserId);
|
||||
}
|
||||
@@ -161,7 +154,7 @@ public class UserInfoStore {
|
||||
* Returns the user id of the current user.
|
||||
*/
|
||||
@UserIdInt
|
||||
public synchronized int getCurrentUserId() {
|
||||
public int getCurrentUserId() {
|
||||
return mCurrentUserId;
|
||||
}
|
||||
|
||||
@@ -169,9 +162,10 @@ public class UserInfoStore {
|
||||
* Returns true if the given user id is either the current user or a profile of the current
|
||||
* user.
|
||||
*/
|
||||
public synchronized boolean isCurrentUserOrProfile(@UserIdInt int userId) {
|
||||
return userId == mCurrentUserId || ArrayUtils.contains(
|
||||
getProfileUserIdsForParentUser(mCurrentUserId), userId);
|
||||
public boolean isCurrentUserOrProfile(@UserIdInt int userId) {
|
||||
int currentUserId = mCurrentUserId;
|
||||
return userId == currentUserId || ArrayUtils.contains(
|
||||
getProfileUserIdsForParentUser(currentUserId), userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,50 +173,44 @@ public class UserInfoStore {
|
||||
* is a parent or has no profiles.
|
||||
*/
|
||||
@UserIdInt
|
||||
public synchronized int getParentUserId(@UserIdInt int userId) {
|
||||
int parentUserId;
|
||||
if (userId == mCachedParentUserId || ArrayUtils.contains(mCachedProfileUserIds, userId)) {
|
||||
parentUserId = mCachedParentUserId;
|
||||
} else {
|
||||
Preconditions.checkState(mUserManager != null);
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
UserInfo userInfo = mUserManager.getProfileParent(userId);
|
||||
if (userInfo != null) {
|
||||
parentUserId = userInfo.id;
|
||||
} else {
|
||||
// getProfileParent() returns null if the userId is already the parent...
|
||||
parentUserId = userId;
|
||||
}
|
||||
|
||||
// force profiles into cache
|
||||
getProfileUserIdsForParentUser(parentUserId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
public int getParentUserId(@UserIdInt int userId) {
|
||||
synchronized (this) {
|
||||
if (userId == mCachedParentUserId || ArrayUtils.contains(mCachedProfileUserIds,
|
||||
userId)) {
|
||||
return mCachedParentUserId;
|
||||
}
|
||||
|
||||
Preconditions.checkState(mUserManager != null);
|
||||
}
|
||||
|
||||
int parentUserId;
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
UserInfo userInfo = mUserManager.getProfileParent(userId);
|
||||
parentUserId = userInfo != null ? userInfo.id : userId;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
|
||||
// force profiles into cache
|
||||
getProfileUserIdsForParentUser(parentUserId);
|
||||
return parentUserId;
|
||||
}
|
||||
|
||||
@GuardedBy("this")
|
||||
private int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
|
||||
Preconditions.checkState(mUserManager != null);
|
||||
|
||||
// only assert on debug builds as this is a more expensive check
|
||||
if (Build.IS_DEBUGGABLE) {
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
Preconditions.checkArgument(mUserManager.getProfileParent(parentUserId) == null);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
|
||||
if (parentUserId != mCachedParentUserId) {
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
Preconditions.checkState(mUserManager != null);
|
||||
|
||||
// more expensive check - check that argument really is a parent user id
|
||||
if (Build.IS_DEBUGGABLE) {
|
||||
Preconditions.checkArgument(
|
||||
mUserManager.getProfileParent(parentUserId) == null);
|
||||
}
|
||||
|
||||
mCachedParentUserId = parentUserId;
|
||||
mCachedProfileUserIds = mUserManager.getProfileIdsWithDisabled(parentUserId);
|
||||
} finally {
|
||||
@@ -236,8 +224,9 @@ public class UserInfoStore {
|
||||
/**
|
||||
* Dump info for debugging.
|
||||
*/
|
||||
public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println("Current User: " + mCurrentUserId + " " + Arrays.toString(
|
||||
getProfileUserIdsForParentUser(mCurrentUserId)));
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
int currentUserId = mCurrentUserId;
|
||||
pw.println("Current User: " + currentUserId + " " + Arrays.toString(
|
||||
getProfileUserIdsForParentUser(currentUserId)));
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
package com.android.server.location.gnss;
|
||||
|
||||
import static android.app.AppOpsManager.OP_FINE_LOCATION;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.location.GnssCapabilities;
|
||||
@@ -31,8 +32,8 @@ import android.location.IGnssStatusListener;
|
||||
import android.location.IGpsGeofenceHardware;
|
||||
import android.location.INetInitiatedListener;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManagerInternal;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.Process;
|
||||
@@ -43,13 +44,12 @@ import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.FgThread;
|
||||
import com.android.server.LocationManagerService;
|
||||
import com.android.server.LocationManagerServiceUtils;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.LocationManagerServiceUtils.LinkedListener;
|
||||
import com.android.server.LocationManagerServiceUtils.LinkedListenerBase;
|
||||
import com.android.server.location.AppForegroundHelper;
|
||||
import com.android.server.location.CallerIdentity;
|
||||
import com.android.server.location.GnssBatchingProvider;
|
||||
import com.android.server.location.GnssCapabilitiesProvider;
|
||||
@@ -60,6 +60,7 @@ import com.android.server.location.GnssNavigationMessageProvider;
|
||||
import com.android.server.location.GnssStatusListenerHelper;
|
||||
import com.android.server.location.LocationUsageLogger;
|
||||
import com.android.server.location.RemoteListenerHelper;
|
||||
import com.android.server.location.SettingsHelper;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -70,10 +71,18 @@ import java.util.function.Function;
|
||||
|
||||
/** Manages Gnss providers and related Gnss functions for LocationManagerService. */
|
||||
public class GnssManagerService {
|
||||
private static final String TAG = "GnssManagerService";
|
||||
private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
// Providers
|
||||
private static final String TAG = "GnssManagerService";
|
||||
|
||||
public static boolean isGnssSupported() {
|
||||
return GnssLocationProvider.isSupported();
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
private final SettingsHelper mSettingsHelper;
|
||||
private final AppForegroundHelper mAppForegroundHelper;
|
||||
private final LocationUsageLogger mLocationUsageLogger;
|
||||
|
||||
private final GnssLocationProvider mGnssLocationProvider;
|
||||
private final GnssStatusListenerHelper mGnssStatusProvider;
|
||||
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
|
||||
@@ -83,58 +92,59 @@ public class GnssManagerService {
|
||||
private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
|
||||
private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
|
||||
private final GnssBatchingProvider mGnssBatchingProvider;
|
||||
|
||||
private final INetInitiatedListener mNetInitiatedListener;
|
||||
private final IGpsGeofenceHardware mGpsGeofenceProxy;
|
||||
private final LocationManagerService mLocationManagerService;
|
||||
private final LocationUsageLogger mLocationUsageLogger;
|
||||
|
||||
@GuardedBy("mGnssMeasurementsListeners")
|
||||
private final ArrayMap<IBinder,
|
||||
LinkedListener<IGnssMeasurementsListener>>
|
||||
private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>>
|
||||
mGnssMeasurementsListeners = new ArrayMap<>();
|
||||
|
||||
@GuardedBy("mGnssNavigationMessageListeners")
|
||||
private final ArrayMap<
|
||||
IBinder, LinkedListener<IGnssNavigationMessageListener>>
|
||||
private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>>
|
||||
mGnssNavigationMessageListeners = new ArrayMap<>();
|
||||
|
||||
@GuardedBy("mGnssStatusListeners")
|
||||
private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>>
|
||||
mGnssStatusListeners = new ArrayMap<>();
|
||||
|
||||
@GuardedBy("mGnssBatchingLock")
|
||||
private IBatchedLocationCallback mGnssBatchingCallback;
|
||||
@GuardedBy("this")
|
||||
@Nullable private LocationManagerInternal mLocationManagerInternal;
|
||||
@GuardedBy("this")
|
||||
@Nullable private AppOpsManager mAppOpsManager;
|
||||
|
||||
private final Object mGnssBatchingLock = new Object();
|
||||
|
||||
@GuardedBy("mGnssBatchingLock")
|
||||
private LinkedListener<IBatchedLocationCallback>
|
||||
mGnssBatchingDeathCallback;
|
||||
@Nullable private IBatchedLocationCallback mGnssBatchingCallback;
|
||||
|
||||
@GuardedBy("mGnssBatchingLock")
|
||||
@Nullable private LinkedListener<IBatchedLocationCallback> mGnssBatchingDeathCallback;
|
||||
|
||||
@GuardedBy("mGnssBatchingLock")
|
||||
private boolean mGnssBatchingInProgress = false;
|
||||
|
||||
private final Object mGnssBatchingLock = new Object();
|
||||
private final Context mContext;
|
||||
private final Handler mHandler;
|
||||
|
||||
public GnssManagerService(LocationManagerService locationManagerService,
|
||||
Context context, LocationUsageLogger locationUsageLogger) {
|
||||
this(locationManagerService, context,
|
||||
new GnssLocationProvider(context, FgThread.getHandler()), locationUsageLogger);
|
||||
public GnssManagerService(Context context, SettingsHelper settingsHelper,
|
||||
AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger) {
|
||||
this(context, settingsHelper, appForegroundHelper, locationUsageLogger, null);
|
||||
}
|
||||
|
||||
// Can use this constructor to inject GnssLocationProvider for testing
|
||||
@VisibleForTesting
|
||||
public GnssManagerService(LocationManagerService locationManagerService,
|
||||
Context context,
|
||||
GnssLocationProvider gnssLocationProvider,
|
||||
LocationUsageLogger locationUsageLogger) {
|
||||
GnssManagerService(Context context, SettingsHelper settingsHelper,
|
||||
AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger,
|
||||
GnssLocationProvider gnssLocationProvider) {
|
||||
Preconditions.checkState(isGnssSupported());
|
||||
|
||||
mContext = context;
|
||||
mHandler = FgThread.getHandler();
|
||||
mSettingsHelper = settingsHelper;
|
||||
mAppForegroundHelper = appForegroundHelper;
|
||||
mLocationUsageLogger = locationUsageLogger;
|
||||
|
||||
mGnssLocationProvider =
|
||||
gnssLocationProvider;
|
||||
if (gnssLocationProvider == null) {
|
||||
gnssLocationProvider = new GnssLocationProvider(mContext);
|
||||
}
|
||||
|
||||
mGnssLocationProvider = gnssLocationProvider;
|
||||
mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider();
|
||||
mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider();
|
||||
mGnssMeasurementCorrectionsProvider =
|
||||
@@ -144,108 +154,73 @@ public class GnssManagerService {
|
||||
mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider();
|
||||
mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider();
|
||||
mGnssBatchingProvider = mGnssLocationProvider.getGnssBatchingProvider();
|
||||
|
||||
mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener();
|
||||
mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy();
|
||||
mLocationManagerService = locationManagerService;
|
||||
mLocationUsageLogger = locationUsageLogger;
|
||||
|
||||
registerUidListener();
|
||||
}
|
||||
|
||||
public static boolean isGnssSupported() {
|
||||
return GnssLocationProvider.isSupported();
|
||||
}
|
||||
|
||||
private boolean hasGnssPermissions(String packageName) {
|
||||
mContext.enforceCallingPermission(
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
"Fine location permission not granted.");
|
||||
|
||||
int uid = Binder.getCallingUid();
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mContext.getSystemService(
|
||||
AppOpsManager.class).checkOp(AppOpsManager.OP_FINE_LOCATION, uid, packageName)
|
||||
== AppOpsManager.MODE_ALLOWED;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
/** Called when system is ready. */
|
||||
public synchronized void onSystemReady() {
|
||||
if (mLocationManagerInternal != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSettingsHelper.onSystemReady();
|
||||
mAppForegroundHelper.onSystemReady();
|
||||
|
||||
mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class);
|
||||
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
|
||||
|
||||
mAppForegroundHelper.addListener(this::onAppForegroundChanged);
|
||||
}
|
||||
|
||||
/** Retrieve the GnssLocationProvider. */
|
||||
public GnssLocationProvider getGnssLocationProvider() {
|
||||
return mGnssLocationProvider;
|
||||
}
|
||||
|
||||
/** Retrieve the IGpsGeofenceHardware. */
|
||||
public IGpsGeofenceHardware getGpsGeofenceProxy() {
|
||||
return mGpsGeofenceProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get year of GNSS hardware.
|
||||
*
|
||||
* @return year of GNSS hardware as an int if possible, otherwise zero
|
||||
*/
|
||||
public int getGnssYearOfHardware() {
|
||||
if (mGnssSystemInfoProvider != null) {
|
||||
return mGnssSystemInfoProvider.getGnssYearOfHardware();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return mGnssSystemInfoProvider.getGnssYearOfHardware();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get model name of GNSS hardware.
|
||||
*
|
||||
* @return GNSS hardware model name as a string if possible, otherwise null
|
||||
*/
|
||||
@Nullable
|
||||
public String getGnssHardwareModelName() {
|
||||
if (mGnssSystemInfoProvider != null) {
|
||||
return mGnssSystemInfoProvider.getGnssHardwareModelName();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return mGnssSystemInfoProvider.getGnssHardwareModelName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GNSS hardware capabilities. The capabilities are described in {@link
|
||||
* android.location.GnssCapabilities} and their integer values correspond to the
|
||||
* bit positions in the returned {@code long} value.
|
||||
*
|
||||
* @param packageName name of requesting package
|
||||
* @return capabilities supported by the GNSS chipset
|
||||
* Get GNSS hardware capabilities. The capabilities returned are a bitfield as described in
|
||||
* {@link android.location.GnssCapabilities}.
|
||||
*/
|
||||
public long getGnssCapabilities(String packageName) {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to obtain GNSS chipset capabilities.");
|
||||
if (!hasGnssPermissions(packageName) || mGnssCapabilitiesProvider == null) {
|
||||
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
|
||||
mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
|
||||
|
||||
if (!checkLocationAppOp(packageName)) {
|
||||
return GnssCapabilities.INVALID_CAPABILITIES;
|
||||
}
|
||||
|
||||
return mGnssCapabilitiesProvider.getGnssCapabilities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of GNSS batch (GNSS location results are batched together for power savings).
|
||||
* Requires LOCATION_HARDWARE and GNSS permissions.
|
||||
*
|
||||
* @param packageName name of requesting package
|
||||
* @return size of the GNSS batch collection
|
||||
*/
|
||||
public int getGnssBatchSize(String packageName) {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to access hardware batching");
|
||||
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
|
||||
mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
|
||||
|
||||
if (!hasGnssPermissions(packageName)) {
|
||||
Log.e(TAG, "getGnssBatchSize called without GNSS permissions");
|
||||
return 0;
|
||||
}
|
||||
if (mGnssBatchingProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Can not get GNSS batch size. GNSS batching provider "
|
||||
+ "not available.");
|
||||
if (!checkLocationAppOp(packageName)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -257,27 +232,12 @@ public class GnssManagerService {
|
||||
/**
|
||||
* Starts GNSS batch collection. GNSS positions are collected in a batch before being delivered
|
||||
* as a collection.
|
||||
*
|
||||
* @param periodNanos duration over which to collect GPS positions before delivering as a
|
||||
* batch
|
||||
* @param wakeOnFifoFull specifying whether to wake on full queue
|
||||
* @param packageName name of requesting package
|
||||
* @return true of batch started successfully, false otherwise
|
||||
*/
|
||||
public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to access hardware batching");
|
||||
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
|
||||
mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
|
||||
|
||||
if (!hasGnssPermissions(packageName)) {
|
||||
Log.e(TAG, "startGnssBatch called without GNSS permissions");
|
||||
return false;
|
||||
}
|
||||
if (mGnssBatchingProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Can not start GNSS batching. GNSS batching provider "
|
||||
+ "not available.");
|
||||
if (!checkLocationAppOp(packageName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -285,7 +245,6 @@ public class GnssManagerService {
|
||||
if (mGnssBatchingInProgress) {
|
||||
// Current design does not expect multiple starts to be called repeatedly
|
||||
Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
|
||||
// Try to clean up anyway, and continue
|
||||
stopGnssBatch();
|
||||
}
|
||||
|
||||
@@ -296,26 +255,13 @@ public class GnssManagerService {
|
||||
|
||||
/**
|
||||
* Adds a GNSS batching callback for delivering GNSS location batch results.
|
||||
*
|
||||
* @param callback called when batching operation is complete to deliver GPS positions
|
||||
* @param packageName name of requesting package
|
||||
* @return true if callback is successfully added, false otherwise
|
||||
*/
|
||||
public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
|
||||
@Nullable String featureId, @NonNull String listenerIdentity) {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to access hardware batching");
|
||||
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
|
||||
mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
|
||||
|
||||
if (!hasGnssPermissions(packageName)) {
|
||||
Log.e(TAG, "addGnssBatchingCallback called without GNSS permissions");
|
||||
return false;
|
||||
}
|
||||
if (mGnssBatchingProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Can not add GNSS batching callback. GNSS batching provider "
|
||||
+ "not available.");
|
||||
if (!checkLocationAppOp(packageName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -333,11 +279,9 @@ public class GnssManagerService {
|
||||
stopGnssBatch();
|
||||
removeGnssBatchingCallback();
|
||||
});
|
||||
if (!mGnssBatchingDeathCallback.linkToListenerDeathNotificationLocked(
|
||||
callback.asBinder())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
return mGnssBatchingDeathCallback.linkToListenerDeathNotificationLocked(
|
||||
callback.asBinder());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,27 +291,14 @@ public class GnssManagerService {
|
||||
* @param packageName name of requesting package
|
||||
*/
|
||||
public void flushGnssBatch(String packageName) {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to access hardware batching");
|
||||
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
|
||||
mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
|
||||
|
||||
if (!hasGnssPermissions(packageName)) {
|
||||
Log.e(TAG, "flushGnssBatch called without GNSS permissions");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mGnssBatchingProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Can not flush GNSS batch. GNSS batching provider "
|
||||
+ "not available.");
|
||||
if (!checkLocationAppOp(packageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mGnssBatchingLock) {
|
||||
if (!mGnssBatchingInProgress) {
|
||||
Log.w(TAG, "flushGnssBatch called with no batch in progress");
|
||||
}
|
||||
mGnssBatchingProvider.flush();
|
||||
}
|
||||
}
|
||||
@@ -376,17 +307,7 @@ public class GnssManagerService {
|
||||
* Removes GNSS batching callback.
|
||||
*/
|
||||
public void removeGnssBatchingCallback() {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to access hardware batching");
|
||||
|
||||
if (mGnssBatchingProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Can not add GNSS batching callback. GNSS batching provider "
|
||||
+ "not available.");
|
||||
return;
|
||||
}
|
||||
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
|
||||
|
||||
synchronized (mGnssBatchingLock) {
|
||||
mGnssBatchingDeathCallback.unlinkFromListenerDeathNotificationLocked(
|
||||
@@ -398,44 +319,17 @@ public class GnssManagerService {
|
||||
|
||||
/**
|
||||
* Stop GNSS batch collection.
|
||||
*
|
||||
* @return true if GNSS batch successfully stopped, false otherwise
|
||||
*/
|
||||
public boolean stopGnssBatch() {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to access hardware batching");
|
||||
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
|
||||
|
||||
if (mGnssBatchingProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Can not stop GNSS batch. GNSS batching provider "
|
||||
+ "not available.");
|
||||
return false;
|
||||
}
|
||||
synchronized (mGnssBatchingLock) {
|
||||
mGnssBatchingInProgress = false;
|
||||
return mGnssBatchingProvider.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void registerUidListener() {
|
||||
mContext.getSystemService(
|
||||
ActivityManager.class).addOnUidImportanceListener(
|
||||
(uid, importance) -> {
|
||||
// listener invoked on ui thread, move to our thread to reduce risk
|
||||
// of blocking ui thread
|
||||
mHandler.post(
|
||||
() -> {
|
||||
onForegroundChanged(uid,
|
||||
LocationManagerServiceUtils.isImportanceForeground(
|
||||
importance));
|
||||
});
|
||||
},
|
||||
ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
|
||||
}
|
||||
|
||||
private void onForegroundChanged(int uid, boolean foreground) {
|
||||
private void onAppForegroundChanged(int uid, boolean foreground) {
|
||||
synchronized (mGnssMeasurementsListeners) {
|
||||
updateListenersOnForegroundChangedLocked(
|
||||
mGnssMeasurementsListeners,
|
||||
@@ -463,8 +357,7 @@ public class GnssManagerService {
|
||||
}
|
||||
|
||||
private <TListener extends IInterface> void updateListenersOnForegroundChangedLocked(
|
||||
ArrayMap<IBinder, ? extends LinkedListenerBase>
|
||||
gnssDataListeners,
|
||||
Map<IBinder, ? extends LinkedListenerBase> gnssDataListeners,
|
||||
RemoteListenerHelper<TListener> gnssDataProvider,
|
||||
Function<IBinder, TListener> mapBinderToListener,
|
||||
int uid,
|
||||
@@ -477,18 +370,8 @@ public class GnssManagerService {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (D) {
|
||||
Log.d(
|
||||
TAG,
|
||||
linkedListener.getListenerName()
|
||||
+ " from uid "
|
||||
+ uid
|
||||
+ " is now "
|
||||
+ LocationManagerServiceUtils.foregroundAsString(foreground));
|
||||
}
|
||||
|
||||
TListener listener = mapBinderToListener.apply(entry.getKey());
|
||||
if (foreground || mLocationManagerService.isThrottlingExemptLocked(callerIdentity)) {
|
||||
if (foreground || isThrottlingExempt(callerIdentity)) {
|
||||
gnssDataProvider.addListener(listener, callerIdentity);
|
||||
} else {
|
||||
gnssDataProvider.removeListener(listener);
|
||||
@@ -502,67 +385,49 @@ public class GnssManagerService {
|
||||
@Nullable String featureId,
|
||||
@NonNull String listenerIdentifier,
|
||||
RemoteListenerHelper<TListener> gnssDataProvider,
|
||||
ArrayMap<IBinder,
|
||||
LinkedListener<TListener>> gnssDataListeners,
|
||||
ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners,
|
||||
Consumer<TListener> binderDeathCallback) {
|
||||
if (!hasGnssPermissions(packageName)) {
|
||||
Log.e(TAG, "addGnssDataListenerLocked called without GNSS permissions");
|
||||
mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
|
||||
|
||||
if (!checkLocationAppOp(packageName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gnssDataProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Can not add GNSS data listener. GNSS data provider "
|
||||
+ "not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CallerIdentity callerIdentity =
|
||||
new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), packageName,
|
||||
featureId, listenerIdentifier);
|
||||
LinkedListener<TListener> linkedListener =
|
||||
new LocationManagerServiceUtils.LinkedListener<>(
|
||||
listener, listenerIdentifier, callerIdentity, binderDeathCallback);
|
||||
CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
|
||||
Binder.getCallingPid(), packageName, featureId, listenerIdentifier);
|
||||
LinkedListener<TListener> linkedListener = new LinkedListener<>(listener,
|
||||
listenerIdentifier, callerIdentity, binderDeathCallback);
|
||||
IBinder binder = listener.asBinder();
|
||||
if (!linkedListener.linkToListenerDeathNotificationLocked(binder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gnssDataListeners.put(binder, linkedListener);
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (gnssDataProvider == mGnssMeasurementsProvider
|
||||
|| gnssDataProvider == mGnssStatusProvider) {
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_STARTED,
|
||||
gnssDataProvider == mGnssMeasurementsProvider
|
||||
? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
|
||||
: LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
|
||||
packageName,
|
||||
/* LocationRequest= */ null,
|
||||
/* hasListener= */ true,
|
||||
/* hasIntent= */ false,
|
||||
/* geofence= */ null,
|
||||
LocationManagerServiceUtils.getPackageImportance(packageName,
|
||||
mContext));
|
||||
}
|
||||
if (mLocationManagerService.isThrottlingExemptLocked(callerIdentity)
|
||||
|| LocationManagerServiceUtils.isImportanceForeground(
|
||||
LocationManagerServiceUtils.getPackageImportance(packageName, mContext))) {
|
||||
gnssDataProvider.addListener(listener, callerIdentity);
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
if (gnssDataProvider == mGnssMeasurementsProvider
|
||||
|| gnssDataProvider == mGnssStatusProvider) {
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_STARTED,
|
||||
gnssDataProvider == mGnssMeasurementsProvider
|
||||
? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
|
||||
: LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
|
||||
packageName,
|
||||
/* LocationRequest= */ null,
|
||||
/* hasListener= */ true,
|
||||
/* hasIntent= */ false,
|
||||
/* geofence= */ null,
|
||||
mAppForegroundHelper.getImportance(callerIdentity.mUid));
|
||||
}
|
||||
if (mAppForegroundHelper.isAppForeground(callerIdentity.mUid)
|
||||
|| isThrottlingExempt(callerIdentity)) {
|
||||
gnssDataProvider.addListener(listener, callerIdentity);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private <TListener extends IInterface> void removeGnssDataListener(
|
||||
private <TListener extends IInterface> void removeGnssDataListenerLocked(
|
||||
TListener listener,
|
||||
RemoteListenerHelper<TListener> gnssDataProvider,
|
||||
ArrayMap<IBinder,
|
||||
LinkedListener<TListener>> gnssDataListeners) {
|
||||
ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners) {
|
||||
if (gnssDataProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
@@ -577,25 +442,19 @@ public class GnssManagerService {
|
||||
if (linkedListener == null) {
|
||||
return;
|
||||
}
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (gnssDataProvider == mGnssMeasurementsProvider
|
||||
|| gnssDataProvider == mGnssStatusProvider) {
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_ENDED,
|
||||
gnssDataProvider == mGnssMeasurementsProvider
|
||||
? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
|
||||
: LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
|
||||
linkedListener.getCallerIdentity().mPackageName,
|
||||
/* LocationRequest= */ null,
|
||||
/* hasListener= */ true,
|
||||
/* hasIntent= */ false,
|
||||
/* geofence= */ null,
|
||||
LocationManagerServiceUtils.getPackageImportance(
|
||||
linkedListener.getCallerIdentity().mPackageName, mContext));
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
if (gnssDataProvider == mGnssMeasurementsProvider
|
||||
|| gnssDataProvider == mGnssStatusProvider) {
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_ENDED,
|
||||
gnssDataProvider == mGnssMeasurementsProvider
|
||||
? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
|
||||
: LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
|
||||
linkedListener.getCallerIdentity().mPackageName,
|
||||
/* LocationRequest= */ null,
|
||||
/* hasListener= */ true,
|
||||
/* hasIntent= */ false,
|
||||
/* geofence= */ null,
|
||||
mAppForegroundHelper.getImportance(Binder.getCallingUid()));
|
||||
}
|
||||
linkedListener.unlinkFromListenerDeathNotificationLocked(binder);
|
||||
gnssDataProvider.removeListener(listener);
|
||||
@@ -603,10 +462,6 @@ public class GnssManagerService {
|
||||
|
||||
/**
|
||||
* Registers listener for GNSS status changes.
|
||||
*
|
||||
* @param listener called when GNSS status changes
|
||||
* @param packageName name of requesting package
|
||||
* @return true if listener is successfully registered, false otherwise
|
||||
*/
|
||||
public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
|
||||
@Nullable String featureId) {
|
||||
@@ -624,21 +479,15 @@ public class GnssManagerService {
|
||||
|
||||
/**
|
||||
* Unregisters listener for GNSS status changes.
|
||||
*
|
||||
* @param listener called when GNSS status changes
|
||||
*/
|
||||
public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
|
||||
synchronized (mGnssStatusListeners) {
|
||||
removeGnssDataListener(listener, mGnssStatusProvider, mGnssStatusListeners);
|
||||
removeGnssDataListenerLocked(listener, mGnssStatusProvider, mGnssStatusListeners);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a GNSS measurements listener.
|
||||
*
|
||||
* @param listener called when GNSS measurements are received
|
||||
* @param packageName name of requesting package
|
||||
* @return true if listener is successfully added, false otherwise
|
||||
*/
|
||||
public boolean addGnssMeasurementsListener(
|
||||
IGnssMeasurementsListener listener, String packageName, @Nullable String featureId,
|
||||
@@ -657,47 +506,32 @@ public class GnssManagerService {
|
||||
|
||||
/**
|
||||
* Injects GNSS measurement corrections.
|
||||
*
|
||||
* @param measurementCorrections GNSS measurement corrections
|
||||
* @param packageName name of requesting package
|
||||
*/
|
||||
public void injectGnssMeasurementCorrections(
|
||||
GnssMeasurementCorrections measurementCorrections, String packageName) {
|
||||
mContext.enforceCallingPermission(
|
||||
android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to inject GNSS measurement corrections.");
|
||||
if (!hasGnssPermissions(packageName)) {
|
||||
Log.e(TAG, "Can not inject GNSS corrections due to no permission.");
|
||||
return;
|
||||
}
|
||||
if (mGnssMeasurementCorrectionsProvider == null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Can not inject GNSS corrections. GNSS measurement corrections provider "
|
||||
+ "not available.");
|
||||
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
|
||||
mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
|
||||
|
||||
if (!checkLocationAppOp(packageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
|
||||
measurementCorrections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a GNSS measurements listener.
|
||||
*
|
||||
* @param listener called when GNSS measurements are received
|
||||
*/
|
||||
public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
|
||||
synchronized (mGnssMeasurementsListeners) {
|
||||
removeGnssDataListener(listener, mGnssMeasurementsProvider, mGnssMeasurementsListeners);
|
||||
removeGnssDataListenerLocked(listener, mGnssMeasurementsProvider,
|
||||
mGnssMeasurementsListeners);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a GNSS navigation message listener.
|
||||
*
|
||||
* @param listener called when navigation message is received
|
||||
* @param packageName name of requesting package
|
||||
* @return true if listener is successfully added, false otherwise
|
||||
*/
|
||||
public boolean addGnssNavigationMessageListener(
|
||||
IGnssNavigationMessageListener listener, String packageName,
|
||||
@@ -716,12 +550,10 @@ public class GnssManagerService {
|
||||
|
||||
/**
|
||||
* Removes a GNSS navigation message listener.
|
||||
*
|
||||
* @param listener called when navigation message is received
|
||||
*/
|
||||
public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
|
||||
synchronized (mGnssNavigationMessageListeners) {
|
||||
removeGnssDataListener(
|
||||
removeGnssDataListenerLocked(
|
||||
listener, mGnssNavigationMessageProvider, mGnssNavigationMessageListeners);
|
||||
}
|
||||
}
|
||||
@@ -729,43 +561,62 @@ public class GnssManagerService {
|
||||
/**
|
||||
* Send Ni Response, indicating a location request initiated by a network carrier.
|
||||
*/
|
||||
public boolean sendNiResponse(int notifId, int userResponse) {
|
||||
if (Binder.getCallingUid() != Process.myUid()) {
|
||||
throw new SecurityException(
|
||||
"calling sendNiResponse from outside of the system is not allowed");
|
||||
}
|
||||
public void sendNiResponse(int notifId, int userResponse) {
|
||||
try {
|
||||
return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
|
||||
mNetInitiatedListener.sendNiResponse(notifId, userResponse);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report location results to GNSS batching listener.
|
||||
*
|
||||
* @param locations batch of locations to report to GNSS batching callback
|
||||
*/
|
||||
public void onReportLocation(List<Location> locations) {
|
||||
if (mGnssBatchingCallback == null) {
|
||||
Log.e(TAG, "reportLocationBatch() called without active Callback");
|
||||
IBatchedLocationCallback gnssBatchingCallback;
|
||||
synchronized (mGnssBatchingLock) {
|
||||
gnssBatchingCallback = mGnssBatchingCallback;
|
||||
}
|
||||
|
||||
if (gnssBatchingCallback == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mGnssBatchingCallback.onLocationBatch(locations);
|
||||
gnssBatchingCallback.onLocationBatch(locations);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
|
||||
if (callerIdentity.mUid == Process.SYSTEM_UID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
|
||||
callerIdentity.mPackageName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
Preconditions.checkState(mLocationManagerInternal != null);
|
||||
}
|
||||
return mLocationManagerInternal.isProviderPackage(callerIdentity.mPackageName);
|
||||
}
|
||||
|
||||
private boolean checkLocationAppOp(String packageName) {
|
||||
synchronized (this) {
|
||||
Preconditions.checkState(mAppOpsManager != null);
|
||||
}
|
||||
return mAppOpsManager.checkOp(OP_FINE_LOCATION, Binder.getCallingUid(), packageName)
|
||||
== AppOpsManager.MODE_ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump for debugging.
|
||||
* Dump info for debugging.
|
||||
*/
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
|
||||
|
||||
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
|
||||
|
||||
if (args.length > 0 && args[0].equals("--gnssmetrics")) {
|
||||
@@ -778,11 +629,8 @@ public class GnssManagerService {
|
||||
ipw.println("GnssMeasurement Listeners:");
|
||||
ipw.increaseIndent();
|
||||
synchronized (mGnssMeasurementsListeners) {
|
||||
for (LinkedListenerBase listener :
|
||||
mGnssMeasurementsListeners
|
||||
.values()) {
|
||||
ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
|
||||
listener.getCallerIdentity()));
|
||||
for (LinkedListenerBase listener : mGnssMeasurementsListeners.values()) {
|
||||
ipw.println(listener);
|
||||
}
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
@@ -790,10 +638,8 @@ public class GnssManagerService {
|
||||
ipw.println("GnssNavigationMessage Listeners:");
|
||||
ipw.increaseIndent();
|
||||
synchronized (mGnssNavigationMessageListeners) {
|
||||
for (LinkedListenerBase listener :
|
||||
mGnssNavigationMessageListeners.values()) {
|
||||
ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
|
||||
listener.getCallerIdentity()));
|
||||
for (LinkedListenerBase listener : mGnssNavigationMessageListeners.values()) {
|
||||
ipw.println(listener);
|
||||
}
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
@@ -801,10 +647,8 @@ public class GnssManagerService {
|
||||
ipw.println("GnssStatus Listeners:");
|
||||
ipw.increaseIndent();
|
||||
synchronized (mGnssStatusListeners) {
|
||||
for (LinkedListenerBase listener :
|
||||
mGnssStatusListeners.values()) {
|
||||
ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
|
||||
listener.getCallerIdentity()));
|
||||
for (LinkedListenerBase listener : mGnssStatusListeners.values()) {
|
||||
ipw.println(listener);
|
||||
}
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
|
||||
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
|
||||
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppForegroundHelperTest {
|
||||
|
||||
private static final long TIMEOUT_MS = 5000;
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private ActivityManager mActivityManager;
|
||||
|
||||
private List<ActivityManager.OnUidImportanceListener> mListeners = new ArrayList<>();
|
||||
|
||||
private AppForegroundHelper mHelper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
initMocks(this);
|
||||
|
||||
doReturn(mActivityManager).when(mContext).getSystemService(ActivityManager.class);
|
||||
doAnswer(invocation -> {
|
||||
mListeners.add(invocation.getArgument(0));
|
||||
return null;
|
||||
}).when(mActivityManager).addOnUidImportanceListener(any(
|
||||
ActivityManager.OnUidImportanceListener.class), eq(IMPORTANCE_FOREGROUND_SERVICE));
|
||||
|
||||
mHelper = new AppForegroundHelper(mContext);
|
||||
mHelper.onSystemReady();
|
||||
}
|
||||
|
||||
private void setImportance(int uid, int importance) {
|
||||
doReturn(importance).when(mActivityManager).getUidImportance(uid);
|
||||
for (ActivityManager.OnUidImportanceListener listener : mListeners) {
|
||||
listener.onUidImportance(uid, importance);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListeners() {
|
||||
AppForegroundHelper.AppForegroundListener listener = mock(
|
||||
AppForegroundHelper.AppForegroundListener.class);
|
||||
mHelper.addListener(listener);
|
||||
|
||||
setImportance(0, IMPORTANCE_FOREGROUND);
|
||||
verify(listener, timeout(TIMEOUT_MS)).onAppForegroundChanged(0, true);
|
||||
|
||||
setImportance(1, IMPORTANCE_FOREGROUND_SERVICE);
|
||||
verify(listener, timeout(TIMEOUT_MS)).onAppForegroundChanged(1, true);
|
||||
|
||||
setImportance(2, IMPORTANCE_VISIBLE);
|
||||
verify(listener, timeout(TIMEOUT_MS)).onAppForegroundChanged(2, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAppForeground() {
|
||||
setImportance(0, IMPORTANCE_FOREGROUND);
|
||||
assertThat(mHelper.isAppForeground(0)).isEqualTo(true);
|
||||
|
||||
setImportance(0, IMPORTANCE_FOREGROUND_SERVICE);
|
||||
assertThat(mHelper.isAppForeground(0)).isEqualTo(true);
|
||||
|
||||
setImportance(0, IMPORTANCE_VISIBLE);
|
||||
assertThat(mHelper.isAppForeground(0)).isEqualTo(false);
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ import java.util.List;
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class UserInfoStoreTest {
|
||||
public class UserInfoHelperTest {
|
||||
|
||||
private static final int USER1_ID = 1;
|
||||
private static final int USER1_MANAGED_ID = 11;
|
||||
@@ -72,7 +72,7 @@ public class UserInfoStoreTest {
|
||||
private StaticMockitoSession mMockingSession;
|
||||
private List<BroadcastReceiver> mBroadcastReceivers = new ArrayList<>();
|
||||
|
||||
private UserInfoStore mStore;
|
||||
private UserInfoHelper mHelper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -97,8 +97,8 @@ public class UserInfoStoreTest {
|
||||
|
||||
doReturn(USER1_ID).when(ActivityManager::getCurrentUser);
|
||||
|
||||
mStore = new UserInfoStore(mContext);
|
||||
mStore.onSystemReady();
|
||||
mHelper = new UserInfoHelper(mContext);
|
||||
mHelper.onSystemReady();
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -119,8 +119,9 @@ public class UserInfoStoreTest {
|
||||
|
||||
@Test
|
||||
public void testListeners() {
|
||||
UserInfoStore.UserChangedListener listener = mock(UserInfoStore.UserChangedListener.class);
|
||||
mStore.addListener(listener);
|
||||
UserInfoHelper.UserChangedListener listener = mock(
|
||||
UserInfoHelper.UserChangedListener.class);
|
||||
mHelper.addListener(listener);
|
||||
|
||||
switchUser(USER1_ID);
|
||||
verify(listener, never()).onUserChanged(anyInt(), anyInt());
|
||||
@@ -134,44 +135,44 @@ public class UserInfoStoreTest {
|
||||
|
||||
@Test
|
||||
public void testCurrentUser() {
|
||||
assertThat(mStore.getCurrentUserId()).isEqualTo(USER1_ID);
|
||||
assertThat(mHelper.getCurrentUserId()).isEqualTo(USER1_ID);
|
||||
|
||||
switchUser(USER2_ID);
|
||||
|
||||
assertThat(mStore.getCurrentUserId()).isEqualTo(USER2_ID);
|
||||
assertThat(mHelper.getCurrentUserId()).isEqualTo(USER2_ID);
|
||||
|
||||
switchUser(USER1_ID);
|
||||
|
||||
assertThat(mStore.getCurrentUserId()).isEqualTo(USER1_ID);
|
||||
assertThat(mHelper.getCurrentUserId()).isEqualTo(USER1_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsCurrentUserOrProfile() {
|
||||
assertThat(mStore.isCurrentUserOrProfile(USER1_ID)).isTrue();
|
||||
assertThat(mStore.isCurrentUserOrProfile(USER1_MANAGED_ID)).isTrue();
|
||||
assertThat(mStore.isCurrentUserOrProfile(USER2_ID)).isFalse();
|
||||
assertThat(mStore.isCurrentUserOrProfile(USER2_MANAGED_ID)).isFalse();
|
||||
assertThat(mHelper.isCurrentUserOrProfile(USER1_ID)).isTrue();
|
||||
assertThat(mHelper.isCurrentUserOrProfile(USER1_MANAGED_ID)).isTrue();
|
||||
assertThat(mHelper.isCurrentUserOrProfile(USER2_ID)).isFalse();
|
||||
assertThat(mHelper.isCurrentUserOrProfile(USER2_MANAGED_ID)).isFalse();
|
||||
|
||||
switchUser(USER2_ID);
|
||||
|
||||
assertThat(mStore.isCurrentUserOrProfile(USER1_ID)).isFalse();
|
||||
assertThat(mStore.isCurrentUserOrProfile(USER2_ID)).isTrue();
|
||||
assertThat(mStore.isCurrentUserOrProfile(USER1_MANAGED_ID)).isFalse();
|
||||
assertThat(mStore.isCurrentUserOrProfile(USER2_MANAGED_ID)).isTrue();
|
||||
assertThat(mHelper.isCurrentUserOrProfile(USER1_ID)).isFalse();
|
||||
assertThat(mHelper.isCurrentUserOrProfile(USER2_ID)).isTrue();
|
||||
assertThat(mHelper.isCurrentUserOrProfile(USER1_MANAGED_ID)).isFalse();
|
||||
assertThat(mHelper.isCurrentUserOrProfile(USER2_MANAGED_ID)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParentUserId() {
|
||||
assertThat(mStore.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
|
||||
assertThat(mStore.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
|
||||
assertThat(mStore.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
|
||||
assertThat(mStore.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
|
||||
assertThat(mHelper.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
|
||||
assertThat(mHelper.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
|
||||
assertThat(mHelper.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
|
||||
assertThat(mHelper.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
|
||||
|
||||
switchUser(USER2_ID);
|
||||
|
||||
assertThat(mStore.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
|
||||
assertThat(mStore.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
|
||||
assertThat(mStore.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
|
||||
assertThat(mStore.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
|
||||
assertThat(mHelper.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
|
||||
assertThat(mHelper.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
|
||||
assertThat(mHelper.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
|
||||
assertThat(mHelper.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -31,7 +32,6 @@ import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -46,13 +46,15 @@ import android.location.IGnssNavigationMessageListener;
|
||||
import android.location.IGnssStatusListener;
|
||||
import android.location.INetInitiatedListener;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManagerInternal;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.server.LocationManagerService;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.location.AppForegroundHelper;
|
||||
import com.android.server.location.GnssBatchingProvider;
|
||||
import com.android.server.location.GnssCapabilitiesProvider;
|
||||
import com.android.server.location.GnssLocationProvider;
|
||||
@@ -63,7 +65,9 @@ import com.android.server.location.GnssNavigationMessageProvider;
|
||||
import com.android.server.location.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative;
|
||||
import com.android.server.location.GnssStatusListenerHelper;
|
||||
import com.android.server.location.LocationUsageLogger;
|
||||
import com.android.server.location.SettingsHelper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.AdditionalMatchers;
|
||||
@@ -93,18 +97,20 @@ public class GnssManagerServiceTest {
|
||||
@Mock
|
||||
private GnssMeasurementCorrectionsProvider mMockGnssMeasurementCorrectionsProvider;
|
||||
@Mock
|
||||
private INetInitiatedListener mMockNetInitiatedListener;
|
||||
private INetInitiatedListener mNetInitiatedListener;
|
||||
private GnssMeasurementsProvider mTestGnssMeasurementsProvider;
|
||||
private GnssStatusListenerHelper mTestGnssStatusProvider;
|
||||
private GnssNavigationMessageProvider mTestGnssNavigationMessageProvider;
|
||||
|
||||
// Managers and services
|
||||
@Mock
|
||||
private AppOpsManager mMockAppOpsManager;
|
||||
private AppOpsManager mAppOpsManager;
|
||||
@Mock
|
||||
private ActivityManager mMockActivityManager;
|
||||
private SettingsHelper mSettingsHelper;
|
||||
@Mock
|
||||
private LocationManagerService mMockLocationManagerService;
|
||||
private AppForegroundHelper mAppForegroundHelper;
|
||||
@Mock
|
||||
private LocationManagerInternal mLocationManagerInternal;
|
||||
|
||||
// Context and handler
|
||||
@Mock
|
||||
@@ -113,25 +119,23 @@ public class GnssManagerServiceTest {
|
||||
private Context mMockContext;
|
||||
|
||||
// Class under test
|
||||
private com.android.server.location.gnss.GnssManagerService mGnssManagerService;
|
||||
private GnssManagerService mGnssManagerService;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
GnssLocationProvider.setIsSupportedForTest(true);
|
||||
|
||||
// Set up mock context
|
||||
when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn(
|
||||
Context.APP_OPS_SERVICE);
|
||||
when(mMockContext.getSystemServiceName(ActivityManager.class)).thenReturn(
|
||||
Context.ACTIVITY_SERVICE);
|
||||
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(
|
||||
mMockAppOpsManager);
|
||||
when(mMockContext.getSystemService(
|
||||
eq(Context.ACTIVITY_SERVICE))).thenReturn(
|
||||
mMockActivityManager);
|
||||
mAppOpsManager);
|
||||
enableLocationPermissions();
|
||||
|
||||
when(mAppForegroundHelper.isAppForeground(anyInt())).thenReturn(true);
|
||||
|
||||
LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal);
|
||||
|
||||
// Mock Handler will execute posted runnables immediately
|
||||
when(mMockHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
|
||||
(InvocationOnMock invocation) -> {
|
||||
@@ -164,15 +168,22 @@ public class GnssManagerServiceTest {
|
||||
when(mMockGnssLocationProvider.getGnssNavigationMessageProvider()).thenReturn(
|
||||
mTestGnssNavigationMessageProvider);
|
||||
when(mMockGnssLocationProvider.getNetInitiatedListener()).thenReturn(
|
||||
mMockNetInitiatedListener);
|
||||
mNetInitiatedListener);
|
||||
|
||||
// Setup GnssBatching provider
|
||||
when(mMockGnssBatchingProvider.start(anyLong(), anyBoolean())).thenReturn(true);
|
||||
when(mMockGnssBatchingProvider.stop()).thenReturn(true);
|
||||
|
||||
// Create GnssManagerService
|
||||
mGnssManagerService = new GnssManagerService(mMockLocationManagerService, mMockContext,
|
||||
mMockGnssLocationProvider, new LocationUsageLogger());
|
||||
mGnssManagerService = new GnssManagerService(mMockContext, mSettingsHelper,
|
||||
mAppForegroundHelper, new LocationUsageLogger(),
|
||||
mMockGnssLocationProvider);
|
||||
mGnssManagerService.onSystemReady();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
LocalServices.removeServiceForTest(LocationManagerInternal.class);
|
||||
}
|
||||
|
||||
private void overrideAsBinder(IInterface mockListener) {
|
||||
@@ -225,7 +236,7 @@ public class GnssManagerServiceTest {
|
||||
PackageManager.PERMISSION_GRANTED);
|
||||
|
||||
// AppOpsManager will return true if OP_FINE_LOCATION is checked
|
||||
when(mMockAppOpsManager.checkOp(anyInt(), anyInt(), anyString())).thenAnswer(
|
||||
when(mAppOpsManager.checkOp(anyInt(), anyInt(), anyString())).thenAnswer(
|
||||
(InvocationOnMock invocation) -> {
|
||||
int code = (int) (invocation.getArguments()[0]);
|
||||
if (code == AppOpsManager.OP_FINE_LOCATION) {
|
||||
@@ -237,11 +248,11 @@ public class GnssManagerServiceTest {
|
||||
|
||||
private void disableLocationPermissions() {
|
||||
Mockito.doThrow(new SecurityException()).when(
|
||||
mMockContext).enforceCallingPermission(anyString(), anyString());
|
||||
mMockContext).enforceCallingPermission(anyString(), nullable(String.class));
|
||||
Mockito.doThrow(new SecurityException()).when(
|
||||
mMockContext).checkPermission(anyString(), anyInt(), anyInt());
|
||||
|
||||
when(mMockAppOpsManager.checkOp(anyInt(), anyInt(),
|
||||
when(mAppOpsManager.checkOp(anyInt(), anyInt(),
|
||||
anyString())).thenReturn(AppOpsManager.MODE_ERRORED);
|
||||
}
|
||||
|
||||
@@ -733,14 +744,12 @@ public class GnssManagerServiceTest {
|
||||
|
||||
@Test
|
||||
public void sendNiResponseWithPermissionsTest() throws RemoteException {
|
||||
when(mMockNetInitiatedListener.sendNiResponse(anyInt(), anyInt())).thenReturn(true);
|
||||
|
||||
int notifId = 0;
|
||||
int userResponse = 0;
|
||||
enableLocationPermissions();
|
||||
|
||||
assertThat(mGnssManagerService.sendNiResponse(notifId, userResponse)).isEqualTo(true);
|
||||
mGnssManagerService.sendNiResponse(notifId, userResponse);
|
||||
|
||||
verify(mMockNetInitiatedListener, times(1)).sendNiResponse(notifId, userResponse);
|
||||
verify(mNetInitiatedListener, times(1)).sendNiResponse(notifId, userResponse);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user