1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location.gnss; 18 19 import static android.location.LocationManager.GPS_PROVIDER; 20 21 import static com.android.server.location.LocationPermissions.PERMISSION_FINE; 22 import static com.android.server.location.gnss.GnssManagerService.TAG; 23 24 import android.annotation.Nullable; 25 import android.location.LocationManagerInternal; 26 import android.location.LocationManagerInternal.ProviderEnabledListener; 27 import android.location.util.identity.CallerIdentity; 28 import android.os.Binder; 29 import android.os.Build; 30 import android.os.IBinder; 31 import android.os.IInterface; 32 import android.os.Process; 33 import android.util.ArraySet; 34 35 import com.android.internal.util.Preconditions; 36 import com.android.server.LocalServices; 37 import com.android.server.location.injector.AppForegroundHelper; 38 import com.android.server.location.injector.Injector; 39 import com.android.server.location.injector.LocationPermissionsHelper; 40 import com.android.server.location.injector.SettingsHelper; 41 import com.android.server.location.injector.UserInfoHelper; 42 import com.android.server.location.injector.UserInfoHelper.UserListener; 43 import com.android.server.location.listeners.BinderListenerRegistration; 44 import com.android.server.location.listeners.ListenerMultiplexer; 45 46 import java.util.Collection; 47 import java.util.Objects; 48 49 /** 50 * Manager for all GNSS related listeners. This class handles deactivating listeners that do not 51 * belong to the current user, that do not have the appropriate permissions, or that are not 52 * currently in the foreground. It will also disable listeners if the GNSS provider is disabled. 53 * Listeners must be registered with the associated IBinder as the key, if the IBinder dies, the 54 * registration will automatically be removed. 55 * 56 * @param <TRequest> request type 57 * @param <TListener> listener type 58 * @param <TMergedRegistration> merged registration type 59 */ 60 public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInterface, 61 TMergedRegistration> extends 62 ListenerMultiplexer<IBinder, TListener, 63 GnssListenerMultiplexer<TRequest, TListener, TMergedRegistration> 64 .GnssListenerRegistration, TMergedRegistration> { 65 66 /** 67 * Registration object for GNSS listeners. 68 */ 69 protected class GnssListenerRegistration extends 70 BinderListenerRegistration<TRequest, TListener> { 71 72 // we store these values because we don't trust the listeners not to give us dupes, not to 73 // spam us, and because checking the values may be more expensive 74 private boolean mForeground; 75 private boolean mPermitted; 76 GnssListenerRegistration(@ullable TRequest request, CallerIdentity callerIdentity, TListener listener)77 protected GnssListenerRegistration(@Nullable TRequest request, 78 CallerIdentity callerIdentity, TListener listener) { 79 super(request, callerIdentity, listener); 80 } 81 82 @Override getOwner()83 protected GnssListenerMultiplexer<TRequest, TListener, TMergedRegistration> getOwner() { 84 return GnssListenerMultiplexer.this; 85 } 86 87 /** 88 * Returns true if this registration is currently in the foreground. 89 */ isForeground()90 public boolean isForeground() { 91 return mForeground; 92 } 93 isPermitted()94 boolean isPermitted() { 95 return mPermitted; 96 } 97 98 @Override onBinderListenerRegister()99 protected final void onBinderListenerRegister() { 100 mPermitted = mLocationPermissionsHelper.hasLocationPermissions(PERMISSION_FINE, 101 getIdentity()); 102 mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid()); 103 104 onGnssListenerRegister(); 105 } 106 107 @Override onBinderListenerUnregister()108 protected final void onBinderListenerUnregister() { 109 onGnssListenerUnregister(); 110 } 111 112 /** 113 * May be overridden in place of {@link #onBinderListenerRegister()}. 114 */ onGnssListenerRegister()115 protected void onGnssListenerRegister() {} 116 117 /** 118 * May be overridden in place of {@link #onBinderListenerUnregister()}. 119 */ onGnssListenerUnregister()120 protected void onGnssListenerUnregister() {} 121 onLocationPermissionsChanged(String packageName)122 boolean onLocationPermissionsChanged(String packageName) { 123 if (getIdentity().getPackageName().equals(packageName)) { 124 return onLocationPermissionsChanged(); 125 } 126 127 return false; 128 } 129 onLocationPermissionsChanged(int uid)130 boolean onLocationPermissionsChanged(int uid) { 131 if (getIdentity().getUid() == uid) { 132 return onLocationPermissionsChanged(); 133 } 134 135 return false; 136 } 137 onLocationPermissionsChanged()138 private boolean onLocationPermissionsChanged() { 139 boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(PERMISSION_FINE, 140 getIdentity()); 141 if (permitted != mPermitted) { 142 mPermitted = permitted; 143 return true; 144 } 145 146 return false; 147 } 148 onForegroundChanged(int uid, boolean foreground)149 boolean onForegroundChanged(int uid, boolean foreground) { 150 if (getIdentity().getUid() == uid && foreground != mForeground) { 151 mForeground = foreground; 152 return true; 153 } 154 155 return false; 156 } 157 158 @Override toString()159 public String toString() { 160 StringBuilder builder = new StringBuilder(); 161 builder.append(getIdentity()); 162 163 ArraySet<String> flags = new ArraySet<>(2); 164 if (!mForeground) { 165 flags.add("bg"); 166 } 167 if (!mPermitted) { 168 flags.add("na"); 169 } 170 if (!flags.isEmpty()) { 171 builder.append(" ").append(flags); 172 } 173 174 if (getRequest() != null) { 175 builder.append(" ").append(getRequest()); 176 } 177 return builder.toString(); 178 } 179 } 180 181 protected final UserInfoHelper mUserInfoHelper; 182 protected final SettingsHelper mSettingsHelper; 183 protected final LocationPermissionsHelper mLocationPermissionsHelper; 184 protected final AppForegroundHelper mAppForegroundHelper; 185 protected final LocationManagerInternal mLocationManagerInternal; 186 187 private final UserListener mUserChangedListener = this::onUserChanged; 188 private final ProviderEnabledListener mProviderEnabledChangedListener = 189 this::onProviderEnabledChanged; 190 private final SettingsHelper.GlobalSettingChangedListener 191 mBackgroundThrottlePackageWhitelistChangedListener = 192 this::onBackgroundThrottlePackageWhitelistChanged; 193 private final SettingsHelper.UserSettingChangedListener 194 mLocationPackageBlacklistChangedListener = 195 this::onLocationPackageBlacklistChanged; 196 private final LocationPermissionsHelper.LocationPermissionsListener 197 mLocationPermissionsListener = 198 new LocationPermissionsHelper.LocationPermissionsListener() { 199 @Override 200 public void onLocationPermissionsChanged(String packageName) { 201 GnssListenerMultiplexer.this.onLocationPermissionsChanged(packageName); 202 } 203 204 @Override 205 public void onLocationPermissionsChanged(int uid) { 206 GnssListenerMultiplexer.this.onLocationPermissionsChanged(uid); 207 } 208 }; 209 private final AppForegroundHelper.AppForegroundListener mAppForegroundChangedListener = 210 this::onAppForegroundChanged; 211 GnssListenerMultiplexer(Injector injector)212 protected GnssListenerMultiplexer(Injector injector) { 213 mUserInfoHelper = injector.getUserInfoHelper(); 214 mSettingsHelper = injector.getSettingsHelper(); 215 mLocationPermissionsHelper = injector.getLocationPermissionsHelper(); 216 mAppForegroundHelper = injector.getAppForegroundHelper(); 217 mLocationManagerInternal = Objects.requireNonNull( 218 LocalServices.getService(LocationManagerInternal.class)); 219 } 220 221 @Override getTag()222 public String getTag() { 223 return TAG; 224 } 225 226 /** 227 * May be overridden by subclasses to return whether the service is supported or not. This value 228 * should never change for the lifetime of the multiplexer. If the service is unsupported, all 229 * registrations will be treated as inactive and the backing service will never be registered. 230 * 231 */ isSupported()232 public boolean isSupported() { 233 return true; 234 } 235 236 /** 237 * Adds a listener with the given identity. 238 */ addListener(CallerIdentity identity, TListener listener)239 protected void addListener(CallerIdentity identity, TListener listener) { 240 addListener(null, identity, listener); 241 } 242 243 /** 244 * Adds a listener with the given identity and request. 245 */ addListener(TRequest request, CallerIdentity callerIdentity, TListener listener)246 protected void addListener(TRequest request, CallerIdentity callerIdentity, 247 TListener listener) { 248 final long identity = Binder.clearCallingIdentity(); 249 try { 250 putRegistration(listener.asBinder(), 251 createRegistration(request, callerIdentity, listener)); 252 } finally { 253 Binder.restoreCallingIdentity(identity); 254 } 255 } 256 257 /** 258 * May be overridden by subclasses to change the registration type. 259 */ createRegistration(TRequest request, CallerIdentity callerIdentity, TListener listener)260 protected GnssListenerRegistration createRegistration(TRequest request, 261 CallerIdentity callerIdentity, TListener listener) { 262 return new GnssListenerRegistration(request, callerIdentity, listener); 263 } 264 265 /** 266 * Removes the given listener. 267 */ removeListener(TListener listener)268 public void removeListener(TListener listener) { 269 final long identity = Binder.clearCallingIdentity(); 270 try { 271 removeRegistration(listener.asBinder()); 272 } finally { 273 Binder.restoreCallingIdentity(identity); 274 } 275 } 276 277 @Override isActive(GnssListenerRegistration registration)278 protected boolean isActive(GnssListenerRegistration registration) { 279 if (!isSupported()) { 280 return false; 281 } 282 283 CallerIdentity identity = registration.getIdentity(); 284 return registration.isPermitted() 285 && (registration.isForeground() || isBackgroundRestrictionExempt(identity)) 286 && isActive(identity); 287 } 288 isActive(CallerIdentity identity)289 private boolean isActive(CallerIdentity identity) { 290 if (identity.isSystemServer()) { 291 if (!mLocationManagerInternal.isProviderEnabledForUser(GPS_PROVIDER, 292 mUserInfoHelper.getCurrentUserId())) { 293 return false; 294 } 295 } else { 296 if (!mLocationManagerInternal.isProviderEnabledForUser(GPS_PROVIDER, 297 identity.getUserId())) { 298 return false; 299 } 300 if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) { 301 return false; 302 } 303 if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(), 304 identity.getPackageName())) { 305 return false; 306 } 307 } 308 309 return true; 310 } 311 isBackgroundRestrictionExempt(CallerIdentity identity)312 private boolean isBackgroundRestrictionExempt(CallerIdentity identity) { 313 if (identity.getUid() == Process.SYSTEM_UID) { 314 return true; 315 } 316 317 if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains( 318 identity.getPackageName())) { 319 return true; 320 } 321 322 return mLocationManagerInternal.isProvider(null, identity); 323 } 324 325 // this provides a default implementation for all further subclasses which assumes that there is 326 // never an associated request object, and thus nothing interesting to merge. the majority of 327 // gnss listener multiplexers do not current have associated requests, and the ones that do can 328 // override this implementation. mergeRegistrations( Collection<GnssListenerRegistration> gnssListenerRegistrations)329 protected TMergedRegistration mergeRegistrations( 330 Collection<GnssListenerRegistration> gnssListenerRegistrations) { 331 if (Build.IS_DEBUGGABLE) { 332 for (GnssListenerRegistration registration : gnssListenerRegistrations) { 333 Preconditions.checkState(registration.getRequest() == null); 334 } 335 } 336 337 return null; 338 } 339 340 @Override onRegister()341 protected void onRegister() { 342 if (!isSupported()) { 343 return; 344 } 345 346 mUserInfoHelper.addListener(mUserChangedListener); 347 mLocationManagerInternal.addProviderEnabledListener(GPS_PROVIDER, 348 mProviderEnabledChangedListener); 349 mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener( 350 mBackgroundThrottlePackageWhitelistChangedListener); 351 mSettingsHelper.addOnLocationPackageBlacklistChangedListener( 352 mLocationPackageBlacklistChangedListener); 353 mLocationPermissionsHelper.addListener(mLocationPermissionsListener); 354 mAppForegroundHelper.addListener(mAppForegroundChangedListener); 355 } 356 357 @Override onUnregister()358 protected void onUnregister() { 359 if (!isSupported()) { 360 return; 361 } 362 363 mUserInfoHelper.removeListener(mUserChangedListener); 364 mLocationManagerInternal.removeProviderEnabledListener(GPS_PROVIDER, 365 mProviderEnabledChangedListener); 366 mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener( 367 mBackgroundThrottlePackageWhitelistChangedListener); 368 mSettingsHelper.removeOnLocationPackageBlacklistChangedListener( 369 mLocationPackageBlacklistChangedListener); 370 mLocationPermissionsHelper.removeListener(mLocationPermissionsListener); 371 mAppForegroundHelper.removeListener(mAppForegroundChangedListener); 372 } 373 onUserChanged(int userId, int change)374 private void onUserChanged(int userId, int change) { 375 if (change == UserListener.CURRENT_USER_CHANGED) { 376 updateRegistrations(registration -> registration.getIdentity().getUserId() == userId); 377 } 378 } 379 onProviderEnabledChanged(String provider, int userId, boolean enabled)380 private void onProviderEnabledChanged(String provider, int userId, boolean enabled) { 381 Preconditions.checkState(GPS_PROVIDER.equals(provider)); 382 updateRegistrations(registration -> registration.getIdentity().getUserId() == userId); 383 } 384 onBackgroundThrottlePackageWhitelistChanged()385 private void onBackgroundThrottlePackageWhitelistChanged() { 386 updateRegistrations(registration -> true); 387 } 388 onLocationPackageBlacklistChanged(int userId)389 private void onLocationPackageBlacklistChanged(int userId) { 390 updateRegistrations(registration -> registration.getIdentity().getUserId() == userId); 391 } 392 onLocationPermissionsChanged(String packageName)393 private void onLocationPermissionsChanged(String packageName) { 394 updateRegistrations(registration -> registration.onLocationPermissionsChanged(packageName)); 395 } 396 onLocationPermissionsChanged(int uid)397 private void onLocationPermissionsChanged(int uid) { 398 updateRegistrations(registration -> registration.onLocationPermissionsChanged(uid)); 399 } 400 onAppForegroundChanged(int uid, boolean foreground)401 private void onAppForegroundChanged(int uid, boolean foreground) { 402 updateRegistrations(registration -> registration.onForegroundChanged(uid, foreground)); 403 } 404 405 @Override getServiceState()406 protected String getServiceState() { 407 if (!isSupported()) { 408 return "unsupported"; 409 } else { 410 return super.getServiceState(); 411 } 412 } 413 } 414