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