1 /* 2 * Copyright (C) 2013 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; 18 19 import android.content.Context; 20 import android.hardware.location.GeofenceHardware; 21 import android.hardware.location.GeofenceHardwareImpl; 22 import android.hardware.location.GeofenceHardwareRequestParcelable; 23 import android.hardware.location.IFusedLocationHardware; 24 import android.hardware.location.IFusedLocationHardwareSink; 25 import android.location.FusedBatchOptions; 26 import android.location.IFusedGeofenceHardware; 27 import android.location.Location; 28 import android.location.LocationListener; 29 import android.location.LocationManager; 30 import android.location.LocationRequest; 31 import android.os.Bundle; 32 import android.os.Looper; 33 import android.os.RemoteException; 34 import android.os.SystemClock; 35 import android.util.Log; 36 37 /** 38 * This class is an interop layer for JVM types and the JNI code that interacts 39 * with the FLP HAL implementation. 40 * 41 * {@hide} 42 */ 43 public class FlpHardwareProvider { 44 private static final int FIRST_VERSION_WITH_FLUSH_LOCATIONS = 2; 45 private GeofenceHardwareImpl mGeofenceHardwareSink = null; 46 private IFusedLocationHardwareSink mLocationSink = null; 47 // Capabilities provided by FlpCallbacks 48 private boolean mHaveBatchingCapabilities; 49 private int mBatchingCapabilities; 50 private int mVersion = 1; 51 52 private static FlpHardwareProvider sSingletonInstance = null; 53 54 private final static String TAG = "FlpHardwareProvider"; 55 private final Context mContext; 56 private final Object mLocationSinkLock = new Object(); 57 58 // FlpHal result codes, they must be equal to the ones in fused_location.h 59 private static final int FLP_RESULT_SUCCESS = 0; 60 private static final int FLP_RESULT_ERROR = -1; 61 private static final int FLP_RESULT_INSUFFICIENT_MEMORY = -2; 62 private static final int FLP_RESULT_TOO_MANY_GEOFENCES = -3; 63 private static final int FLP_RESULT_ID_EXISTS = -4; 64 private static final int FLP_RESULT_ID_UNKNOWN = -5; 65 private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6; 66 67 // FlpHal monitor status codes, they must be equal to the ones in fused_location.h 68 private static final int FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE = 1<<0; 69 private static final int FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE = 1<<1; 70 getInstance(Context context)71 public static FlpHardwareProvider getInstance(Context context) { 72 if (sSingletonInstance == null) { 73 sSingletonInstance = new FlpHardwareProvider(context); 74 sSingletonInstance.nativeInit(); 75 } 76 77 return sSingletonInstance; 78 } 79 FlpHardwareProvider(Context context)80 private FlpHardwareProvider(Context context) { 81 mContext = context; 82 83 // register for listening for passive provider data 84 LocationManager manager = (LocationManager) mContext.getSystemService( 85 Context.LOCATION_SERVICE); 86 final long minTime = 0; 87 final float minDistance = 0; 88 final boolean oneShot = false; 89 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 90 LocationManager.PASSIVE_PROVIDER, 91 minTime, 92 minDistance, 93 oneShot); 94 // Don't keep track of this request since it's done on behalf of other clients 95 // (which are kept track of separately). 96 request.setHideFromAppOps(true); 97 manager.requestLocationUpdates( 98 request, 99 new NetworkLocationListener(), 100 Looper.myLooper()); 101 } 102 isSupported()103 public static boolean isSupported() { 104 return nativeIsSupported(); 105 } 106 107 /** 108 * Private callback functions used by FLP HAL. 109 */ 110 // FlpCallbacks members onLocationReport(Location[] locations)111 private void onLocationReport(Location[] locations) { 112 for (Location location : locations) { 113 location.setProvider(LocationManager.FUSED_PROVIDER); 114 // set the elapsed time-stamp just as GPS provider does 115 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 116 } 117 118 IFusedLocationHardwareSink sink; 119 synchronized (mLocationSinkLock) { 120 sink = mLocationSink; 121 } 122 try { 123 if (sink != null) { 124 sink.onLocationAvailable(locations); 125 } 126 } catch (RemoteException e) { 127 Log.e(TAG, "RemoteException calling onLocationAvailable"); 128 } 129 } 130 onBatchingCapabilities(int capabilities)131 private void onBatchingCapabilities(int capabilities) { 132 synchronized (mLocationSinkLock) { 133 mHaveBatchingCapabilities = true; 134 mBatchingCapabilities = capabilities; 135 } 136 137 maybeSendCapabilities(); 138 139 if (mGeofenceHardwareSink != null) { 140 mGeofenceHardwareSink.setVersion(getVersion()); 141 } 142 } 143 onBatchingStatus(int status)144 private void onBatchingStatus(int status) { 145 IFusedLocationHardwareSink sink; 146 synchronized (mLocationSinkLock) { 147 sink = mLocationSink; 148 } 149 try { 150 if (sink != null) { 151 sink.onStatusChanged(status); 152 } 153 } catch (RemoteException e) { 154 Log.e(TAG, "RemoteException calling onBatchingStatus"); 155 } 156 } 157 158 // Returns the current version of the FLP HAL. This depends both on the version of the 159 // structure returned by the hardware layer, and whether or not we've received the 160 // capabilities callback on initialization. Assume original version until we get 161 // the new initialization callback. getVersion()162 private int getVersion() { 163 synchronized (mLocationSinkLock) { 164 if (mHaveBatchingCapabilities) { 165 return mVersion; 166 } 167 } 168 return 1; 169 } 170 setVersion(int version)171 private void setVersion(int version) { 172 mVersion = version; 173 if (mGeofenceHardwareSink != null) { 174 mGeofenceHardwareSink.setVersion(getVersion()); 175 } 176 } 177 maybeSendCapabilities()178 private void maybeSendCapabilities() { 179 IFusedLocationHardwareSink sink; 180 boolean haveBatchingCapabilities; 181 int batchingCapabilities; 182 synchronized (mLocationSinkLock) { 183 sink = mLocationSink; 184 haveBatchingCapabilities = mHaveBatchingCapabilities; 185 batchingCapabilities = mBatchingCapabilities; 186 } 187 try { 188 if (sink != null && haveBatchingCapabilities) { 189 sink.onCapabilities(batchingCapabilities); 190 } 191 } catch (RemoteException e) { 192 Log.e(TAG, "RemoteException calling onLocationAvailable"); 193 } 194 } 195 196 // FlpDiagnosticCallbacks members onDataReport(String data)197 private void onDataReport(String data) { 198 IFusedLocationHardwareSink sink; 199 synchronized (mLocationSinkLock) { 200 sink = mLocationSink; 201 } 202 try { 203 if (mLocationSink != null) { 204 sink.onDiagnosticDataAvailable(data); 205 } 206 } catch (RemoteException e) { 207 Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable"); 208 } 209 } 210 211 // FlpGeofenceCallbacks members onGeofenceTransition( int geofenceId, Location location, int transition, long timestamp, int sourcesUsed)212 private void onGeofenceTransition( 213 int geofenceId, 214 Location location, 215 int transition, 216 long timestamp, 217 int sourcesUsed) { 218 // the transition Id does not require translation because the values in fused_location.h 219 // and GeofenceHardware are in sync 220 getGeofenceHardwareSink().reportGeofenceTransition( 221 geofenceId, 222 updateLocationInformation(location), 223 transition, 224 timestamp, 225 GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, 226 sourcesUsed); 227 } 228 onGeofenceMonitorStatus(int status, int source, Location location)229 private void onGeofenceMonitorStatus(int status, int source, Location location) { 230 // allow the location to be optional in this event 231 Location updatedLocation = null; 232 if(location != null) { 233 updatedLocation = updateLocationInformation(location); 234 } 235 236 int monitorStatus; 237 switch (status) { 238 case FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE: 239 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 240 break; 241 case FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE: 242 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 243 break; 244 default: 245 Log.e(TAG, "Invalid FlpHal Geofence monitor status: " + status); 246 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 247 break; 248 } 249 250 getGeofenceHardwareSink().reportGeofenceMonitorStatus( 251 GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, 252 monitorStatus, 253 updatedLocation, 254 source); 255 } 256 onGeofenceAdd(int geofenceId, int result)257 private void onGeofenceAdd(int geofenceId, int result) { 258 getGeofenceHardwareSink().reportGeofenceAddStatus( 259 geofenceId, 260 translateToGeofenceHardwareStatus(result)); 261 } 262 onGeofenceRemove(int geofenceId, int result)263 private void onGeofenceRemove(int geofenceId, int result) { 264 getGeofenceHardwareSink().reportGeofenceRemoveStatus( 265 geofenceId, 266 translateToGeofenceHardwareStatus(result)); 267 } 268 onGeofencePause(int geofenceId, int result)269 private void onGeofencePause(int geofenceId, int result) { 270 getGeofenceHardwareSink().reportGeofencePauseStatus( 271 geofenceId, 272 translateToGeofenceHardwareStatus(result)); 273 } 274 onGeofenceResume(int geofenceId, int result)275 private void onGeofenceResume(int geofenceId, int result) { 276 getGeofenceHardwareSink().reportGeofenceResumeStatus( 277 geofenceId, 278 translateToGeofenceHardwareStatus(result)); 279 } 280 onGeofencingCapabilities(int capabilities)281 private void onGeofencingCapabilities(int capabilities) { 282 getGeofenceHardwareSink().onCapabilities(capabilities); 283 } 284 285 /** 286 * Private native methods accessing FLP HAL. 287 */ nativeClassInit()288 static { nativeClassInit(); } 289 290 // Core members nativeClassInit()291 private static native void nativeClassInit(); nativeIsSupported()292 private static native boolean nativeIsSupported(); 293 294 // FlpLocationInterface members nativeInit()295 private native void nativeInit(); nativeGetBatchSize()296 private native int nativeGetBatchSize(); nativeStartBatching(int requestId, FusedBatchOptions options)297 private native void nativeStartBatching(int requestId, FusedBatchOptions options); nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject)298 private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject); nativeStopBatching(int id)299 private native void nativeStopBatching(int id); nativeRequestBatchedLocation(int lastNLocations)300 private native void nativeRequestBatchedLocation(int lastNLocations); nativeFlushBatchedLocations()301 private native void nativeFlushBatchedLocations(); nativeInjectLocation(Location location)302 private native void nativeInjectLocation(Location location); nativeCleanup()303 private native void nativeCleanup(); 304 305 // FlpDiagnosticsInterface members nativeIsDiagnosticSupported()306 private native boolean nativeIsDiagnosticSupported(); nativeInjectDiagnosticData(String data)307 private native void nativeInjectDiagnosticData(String data); 308 309 // FlpDeviceContextInterface members nativeIsDeviceContextSupported()310 private native boolean nativeIsDeviceContextSupported(); nativeInjectDeviceContext(int deviceEnabledContext)311 private native void nativeInjectDeviceContext(int deviceEnabledContext); 312 313 // FlpGeofencingInterface members nativeIsGeofencingSupported()314 private native boolean nativeIsGeofencingSupported(); nativeAddGeofences( GeofenceHardwareRequestParcelable[] geofenceRequestsArray)315 private native void nativeAddGeofences( 316 GeofenceHardwareRequestParcelable[] geofenceRequestsArray); nativePauseGeofence(int geofenceId)317 private native void nativePauseGeofence(int geofenceId); nativeResumeGeofence(int geofenceId, int monitorTransitions)318 private native void nativeResumeGeofence(int geofenceId, int monitorTransitions); nativeModifyGeofenceOption( int geofenceId, int lastTransition, int monitorTransitions, int notificationResponsiveness, int unknownTimer, int sourcesToUse)319 private native void nativeModifyGeofenceOption( 320 int geofenceId, 321 int lastTransition, 322 int monitorTransitions, 323 int notificationResponsiveness, 324 int unknownTimer, 325 int sourcesToUse); nativeRemoveGeofences(int[] geofenceIdsArray)326 private native void nativeRemoveGeofences(int[] geofenceIdsArray); 327 328 /** 329 * Interface implementations for services built on top of this functionality. 330 */ 331 public static final String LOCATION = "Location"; 332 public static final String GEOFENCING = "Geofencing"; 333 getLocationHardware()334 public IFusedLocationHardware getLocationHardware() { 335 return mLocationHardware; 336 } 337 getGeofenceHardware()338 public IFusedGeofenceHardware getGeofenceHardware() { 339 return mGeofenceHardwareService; 340 } 341 cleanup()342 public void cleanup() { 343 Log.i(TAG, "Calling nativeCleanup()"); 344 nativeCleanup(); 345 } 346 347 private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() { 348 @Override 349 public void registerSink(IFusedLocationHardwareSink eventSink) { 350 synchronized (mLocationSinkLock) { 351 // only one sink is allowed at the moment 352 if (mLocationSink != null) { 353 Log.e(TAG, "Replacing an existing IFusedLocationHardware sink"); 354 } 355 356 mLocationSink = eventSink; 357 } 358 maybeSendCapabilities(); 359 } 360 361 @Override 362 public void unregisterSink(IFusedLocationHardwareSink eventSink) { 363 synchronized (mLocationSinkLock) { 364 // don't throw if the sink is not registered, simply make it a no-op 365 if (mLocationSink == eventSink) { 366 mLocationSink = null; 367 } 368 } 369 } 370 371 @Override 372 public int getSupportedBatchSize() { 373 return nativeGetBatchSize(); 374 } 375 376 @Override 377 public void startBatching(int requestId, FusedBatchOptions options) { 378 nativeStartBatching(requestId, options); 379 } 380 381 @Override 382 public void stopBatching(int requestId) { 383 nativeStopBatching(requestId); 384 } 385 386 @Override 387 public void updateBatchingOptions(int requestId, FusedBatchOptions options) { 388 nativeUpdateBatchingOptions(requestId, options); 389 } 390 391 @Override 392 public void requestBatchOfLocations(int batchSizeRequested) { 393 nativeRequestBatchedLocation(batchSizeRequested); 394 } 395 396 @Override 397 public void flushBatchedLocations() { 398 if (getVersion() >= FIRST_VERSION_WITH_FLUSH_LOCATIONS) { 399 nativeFlushBatchedLocations(); 400 } else { 401 Log.wtf(TAG, 402 "Tried to call flushBatchedLocations on an unsupported implementation"); 403 } 404 } 405 406 @Override 407 public boolean supportsDiagnosticDataInjection() { 408 return nativeIsDiagnosticSupported(); 409 } 410 411 @Override 412 public void injectDiagnosticData(String data) { 413 nativeInjectDiagnosticData(data); 414 } 415 416 @Override 417 public boolean supportsDeviceContextInjection() { 418 return nativeIsDeviceContextSupported(); 419 } 420 421 @Override 422 public void injectDeviceContext(int deviceEnabledContext) { 423 nativeInjectDeviceContext(deviceEnabledContext); 424 } 425 426 @Override 427 public int getVersion() { 428 return FlpHardwareProvider.this.getVersion(); 429 } 430 }; 431 432 private final IFusedGeofenceHardware mGeofenceHardwareService = 433 new IFusedGeofenceHardware.Stub() { 434 @Override 435 public boolean isSupported() { 436 return nativeIsGeofencingSupported(); 437 } 438 439 @Override 440 public void addGeofences(GeofenceHardwareRequestParcelable[] geofenceRequestsArray) { 441 nativeAddGeofences(geofenceRequestsArray); 442 } 443 444 @Override 445 public void removeGeofences(int[] geofenceIds) { 446 nativeRemoveGeofences(geofenceIds); 447 } 448 449 @Override 450 public void pauseMonitoringGeofence(int geofenceId) { 451 nativePauseGeofence(geofenceId); 452 } 453 454 @Override 455 public void resumeMonitoringGeofence(int geofenceId, int monitorTransitions) { 456 nativeResumeGeofence(geofenceId, monitorTransitions); 457 } 458 459 @Override 460 public void modifyGeofenceOptions(int geofenceId, 461 int lastTransition, 462 int monitorTransitions, 463 int notificationResponsiveness, 464 int unknownTimer, 465 int sourcesToUse) { 466 nativeModifyGeofenceOption( 467 geofenceId, 468 lastTransition, 469 monitorTransitions, 470 notificationResponsiveness, 471 unknownTimer, 472 sourcesToUse); 473 } 474 }; 475 476 /** 477 * Internal classes and functions used by the provider. 478 */ 479 private final class NetworkLocationListener implements LocationListener { 480 @Override onLocationChanged(Location location)481 public void onLocationChanged(Location location) { 482 if ( 483 !LocationManager.NETWORK_PROVIDER.equals(location.getProvider()) || 484 !location.hasAccuracy() 485 ) { 486 return; 487 } 488 489 nativeInjectLocation(location); 490 } 491 492 @Override onStatusChanged(String provider, int status, Bundle extras)493 public void onStatusChanged(String provider, int status, Bundle extras) { } 494 495 @Override onProviderEnabled(String provider)496 public void onProviderEnabled(String provider) { } 497 498 @Override onProviderDisabled(String provider)499 public void onProviderDisabled(String provider) { } 500 } 501 getGeofenceHardwareSink()502 private GeofenceHardwareImpl getGeofenceHardwareSink() { 503 if (mGeofenceHardwareSink == null) { 504 mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext); 505 mGeofenceHardwareSink.setVersion(getVersion()); 506 } 507 508 return mGeofenceHardwareSink; 509 } 510 translateToGeofenceHardwareStatus(int flpHalResult)511 private static int translateToGeofenceHardwareStatus(int flpHalResult) { 512 switch(flpHalResult) { 513 case FLP_RESULT_SUCCESS: 514 return GeofenceHardware.GEOFENCE_SUCCESS; 515 case FLP_RESULT_ERROR: 516 return GeofenceHardware.GEOFENCE_FAILURE; 517 case FLP_RESULT_INSUFFICIENT_MEMORY: 518 return GeofenceHardware.GEOFENCE_ERROR_INSUFFICIENT_MEMORY; 519 case FLP_RESULT_TOO_MANY_GEOFENCES: 520 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 521 case FLP_RESULT_ID_EXISTS: 522 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 523 case FLP_RESULT_ID_UNKNOWN: 524 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 525 case FLP_RESULT_INVALID_GEOFENCE_TRANSITION: 526 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 527 default: 528 Log.e(TAG, String.format("Invalid FlpHal result code: %d", flpHalResult)); 529 return GeofenceHardware.GEOFENCE_FAILURE; 530 } 531 } 532 updateLocationInformation(Location location)533 private Location updateLocationInformation(Location location) { 534 location.setProvider(LocationManager.FUSED_PROVIDER); 535 // set the elapsed time-stamp just as GPS provider does 536 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 537 return location; 538 } 539 } 540