From b27528d066644e9a81ebac27822186fa61c89003 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Thu, 5 Jun 2014 15:02:10 -0700 Subject: [PATCH] Make LocationManagerService aware of user profiles LocationManagerService normally doesn't provide location to background users. With managed profiles, there are more than one foreground users and they both need to get location when in the foreground. So LMS will now compare the caller against all foreground users and provide location if valid. Bug: 14671472 Change-Id: If3baabfc5a3ab3f2f081d7fc28f35d840d5f1489 --- .../server/LocationManagerService.java | 64 ++++++++++++++++--- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 98fa522d49c46..5eee3962fc47e 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -29,6 +29,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; +import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.location.Address; @@ -55,10 +56,12 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; import android.util.Log; import android.util.Slog; + import com.android.internal.content.PackageMonitor; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; @@ -144,6 +147,7 @@ public class LocationManagerService extends ILocationManager.Stub { private GeofenceManager mGeofenceManager; private PackageManager mPackageManager; private PowerManager mPowerManager; + private UserManager mUserManager; private GeocoderProxy mGeocodeProvider; private IGpsStatusProvider mGpsStatusProvider; private INetInitiatedListener mNetInitiatedListener; @@ -197,6 +201,7 @@ public class LocationManagerService extends ILocationManager.Stub { // current active user on the device - other users are denied location data private int mCurrentUserId = UserHandle.USER_OWNER; + private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER }; public LocationManagerService(Context context) { super(); @@ -241,6 +246,9 @@ public class LocationManagerService extends ILocationManager.Stub { }; mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + updateUserProfiles(mCurrentUserId); + // prepare providers loadProvidersLocked(); updateProvidersLocked(); @@ -262,6 +270,8 @@ public class LocationManagerService extends ILocationManager.Stub { // listen for user change IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_SWITCHED); + intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); + intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); mContext.registerReceiverAsUser(new BroadcastReceiver() { @Override @@ -269,11 +279,46 @@ public class LocationManagerService extends ILocationManager.Stub { String action = intent.getAction(); if (Intent.ACTION_USER_SWITCHED.equals(action)) { switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); + } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action) + || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { + updateUserProfiles(mCurrentUserId); } } }, UserHandle.ALL, intentFilter, null, mLocationHandler); } + /** + * Makes a list of userids that are related to the current user. This is + * relevant when using managed profiles. Otherwise the list only contains + * the current user. + * + * @param currentUserId the current user, who might have an alter-ego. + */ + void updateUserProfiles(int currentUserId) { + List profiles = mUserManager.getProfiles(currentUserId); + synchronized (mLock) { + mCurrentUserProfiles = new int[profiles.size()]; + for (int i = 0; i < mCurrentUserProfiles.length; i++) { + mCurrentUserProfiles[i] = profiles.get(i).id; + } + } + } + + /** + * Checks if the specified userId matches any of the current foreground + * users stored in mCurrentUserProfiles. + */ + private boolean isCurrentProfile(int userId) { + synchronized (mLock) { + for (int i = 0; i < mCurrentUserProfiles.length; i++) { + if (mCurrentUserProfiles[i] == userId) { + return true; + } + } + return false; + } + } + private void ensureFallbackFusedProviderPresentLocked(ArrayList pkgs) { PackageManager pm = mContext.getPackageManager(); String systemPackageName = mContext.getPackageName(); @@ -492,9 +537,10 @@ public class LocationManagerService extends ILocationManager.Stub { mLastLocation.clear(); mLastLocationCoarseInterval.clear(); for (LocationProviderInterface p : mProviders) { - updateProviderListenersLocked(p.getName(), false, mCurrentUserId); + updateProviderListenersLocked(p.getName(), false); } mCurrentUserId = userId; + updateUserProfiles(userId); updateProvidersLocked(); } } @@ -894,7 +940,7 @@ public class LocationManagerService extends ILocationManager.Stub { * @return */ private boolean isAllowedByUserSettingsLocked(String provider, int uid) { - if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) { + if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) { return false; } return isAllowedByCurrentUserSettingsLocked(provider); @@ -1181,7 +1227,7 @@ public class LocationManagerService extends ILocationManager.Stub { String name = p.getName(); boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name); if (isEnabled && !shouldBeEnabled) { - updateProviderListenersLocked(name, false, mCurrentUserId); + updateProviderListenersLocked(name, false); // If any provider has been disabled, clear all last locations for all providers. // This is to be on the safe side in case a provider has location derived from // this disabled provider. @@ -1189,7 +1235,7 @@ public class LocationManagerService extends ILocationManager.Stub { mLastLocationCoarseInterval.clear(); changesMade = true; } else if (!isEnabled && shouldBeEnabled) { - updateProviderListenersLocked(name, true, mCurrentUserId); + updateProviderListenersLocked(name, true); changesMade = true; } } @@ -1201,7 +1247,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private void updateProviderListenersLocked(String provider, boolean enabled, int userId) { + private void updateProviderListenersLocked(String provider, boolean enabled) { int listeners = 0; LocationProviderInterface p = mProvidersByName.get(provider); @@ -1214,7 +1260,7 @@ public class LocationManagerService extends ILocationManager.Stub { final int N = records.size(); for (int i = 0; i < N; i++) { UpdateRecord record = records.get(i); - if (UserHandle.getUserId(record.mReceiver.mUid) == userId) { + if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) { // Sends a notification message to the receiver if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { if (deadReceivers == null) { @@ -1253,7 +1299,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (records != null) { for (UpdateRecord record : records) { - if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) { + if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) { if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName, record.mReceiver.mAllowedResolutionLevel)) { LocationRequest locationRequest = record.mRequest; @@ -1274,7 +1320,7 @@ public class LocationManagerService extends ILocationManager.Stub { // under that threshold. long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2; for (UpdateRecord record : records) { - if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) { + if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) { LocationRequest locationRequest = record.mRequest; if (locationRequest.getInterval() <= thresholdInterval) { if (record.mReceiver.mWorkSource != null @@ -2018,7 +2064,7 @@ public class LocationManagerService extends ILocationManager.Stub { boolean receiverDead = false; int receiverUserId = UserHandle.getUserId(receiver.mUid); - if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) { + if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) { if (D) { Log.d(TAG, "skipping loc update for background user " + receiverUserId + " (current user: " + mCurrentUserId + ", app: " +