Merge "Fixed race conditions in GeofenceHardwareImpl." into jb-mr2-dev

This commit is contained in:
Zhentao Sun
2013-04-29 18:50:18 +00:00
committed by Android (Google) Code Review

View File

@@ -48,11 +48,11 @@ public final class GeofenceHardwareImpl {
private final Context mContext; private final Context mContext;
private static GeofenceHardwareImpl sInstance; private static GeofenceHardwareImpl sInstance;
private PowerManager.WakeLock mWakeLock; private PowerManager.WakeLock mWakeLock;
private SparseArray<IGeofenceHardwareCallback> mGeofences = private final SparseArray<IGeofenceHardwareCallback> mGeofences =
new SparseArray<IGeofenceHardwareCallback>(); new SparseArray<IGeofenceHardwareCallback>();
private ArrayList<IGeofenceHardwareMonitorCallback>[] mCallbacks = private final ArrayList<IGeofenceHardwareMonitorCallback>[] mCallbacks =
new ArrayList[GeofenceHardware.NUM_MONITORS]; new ArrayList[GeofenceHardware.NUM_MONITORS];
private ArrayList<Reaper> mReapers = new ArrayList<Reaper>(); private final ArrayList<Reaper> mReapers = new ArrayList<Reaper>();
private IGpsGeofenceHardware mGpsService; private IGpsGeofenceHardware mGpsService;
@@ -64,9 +64,7 @@ public final class GeofenceHardwareImpl {
private static final int REMOVE_GEOFENCE_CALLBACK = 3; private static final int REMOVE_GEOFENCE_CALLBACK = 3;
private static final int PAUSE_GEOFENCE_CALLBACK = 4; private static final int PAUSE_GEOFENCE_CALLBACK = 4;
private static final int RESUME_GEOFENCE_CALLBACK = 5; private static final int RESUME_GEOFENCE_CALLBACK = 5;
private static final int ADD_GEOFENCE = 6; private static final int GEOFENCE_CALLBACK_BINDER_DIED = 6;
private static final int REMOVE_GEOFENCE = 7;
private static final int GEOFENCE_CALLBACK_BINDER_DIED = 8;
// mCallbacksHandler message types // mCallbacksHandler message types
private static final int GPS_GEOFENCE_STATUS = 1; private static final int GPS_GEOFENCE_STATUS = 1;
@@ -186,17 +184,22 @@ public final class GeofenceHardwareImpl {
// This API is not thread safe. Operations on the same geofence need to be serialized // This API is not thread safe. Operations on the same geofence need to be serialized
// by upper layers // by upper layers
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "addCircularFence: GeofenceId: " + geofenceId + "Latitude: " + latitude + Log.d(TAG, "addCircularFence: GeofenceId: " + geofenceId + " Latitude: " + latitude +
"Longitude: " + longitude + "Radius: " + radius + "LastTransition: " " Longitude: " + longitude + " Radius: " + radius + " LastTransition: "
+ lastTransition + "MonitorTransition: " + monitorTransitions + + lastTransition + " MonitorTransition: " + monitorTransitions +
"NotificationResponsiveness: " + notificationResponsivenes + " NotificationResponsiveness: " + notificationResponsivenes +
"UnKnown Timer: " + unknownTimer + "MonitoringType: " + monitoringType); " UnKnown Timer: " + unknownTimer + " MonitoringType: " + monitoringType);
} }
boolean result; boolean result;
Message m = mGeofenceHandler.obtainMessage(ADD_GEOFENCE, callback);
m.arg1 = geofenceId; // The callback must be added before addCircularHardwareGeofence is called otherwise the
mGeofenceHandler.sendMessage(m); // callback might not be called after the geofence is added in the geofence hardware.
// This also means that the callback must be removed if the addCircularHardwareGeofence
// operations is not called or fails.
synchronized (mGeofences) {
mGeofences.put(geofenceId, callback);
}
switch (monitoringType) { switch (monitoringType) {
case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE: case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
@@ -214,13 +217,13 @@ public final class GeofenceHardwareImpl {
result = false; result = false;
} }
if (result) { if (result) {
m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback); Message m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback);
m.arg1 = monitoringType; m.arg1 = monitoringType;
mReaperHandler.sendMessage(m); mReaperHandler.sendMessage(m);
} else { } else {
m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE); synchronized (mGeofences) {
m.arg1 = geofenceId; mGeofences.remove(geofenceId);
mGeofenceHandler.sendMessage(m); }
} }
if (DEBUG) Log.d(TAG, "addCircularFence: Result is: " + result); if (DEBUG) Log.d(TAG, "addCircularFence: Result is: " + result);
@@ -232,6 +235,12 @@ public final class GeofenceHardwareImpl {
// by upper layers // by upper layers
if (DEBUG) Log.d(TAG, "Remove Geofence: GeofenceId: " + geofenceId); if (DEBUG) Log.d(TAG, "Remove Geofence: GeofenceId: " + geofenceId);
boolean result = false; boolean result = false;
synchronized (mGeofences) {
if (mGeofences.get(geofenceId) == null) {
throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
}
}
switch (monitoringType) { switch (monitoringType) {
case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE: case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
if (mGpsService == null) return false; if (mGpsService == null) return false;
@@ -254,6 +263,11 @@ public final class GeofenceHardwareImpl {
// by upper layers // by upper layers
if (DEBUG) Log.d(TAG, "Pause Geofence: GeofenceId: " + geofenceId); if (DEBUG) Log.d(TAG, "Pause Geofence: GeofenceId: " + geofenceId);
boolean result; boolean result;
synchronized (mGeofences) {
if (mGeofences.get(geofenceId) == null) {
throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
}
}
switch (monitoringType) { switch (monitoringType) {
case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE: case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
if (mGpsService == null) return false; if (mGpsService == null) return false;
@@ -277,6 +291,11 @@ public final class GeofenceHardwareImpl {
// by upper layers // by upper layers
if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId); if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId);
boolean result; boolean result;
synchronized (mGeofences) {
if (mGeofences.get(geofenceId) == null) {
throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
}
}
switch (monitoringType) { switch (monitoringType) {
case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE: case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
if (mGpsService == null) return false; if (mGpsService == null) return false;
@@ -446,18 +465,11 @@ public final class GeofenceHardwareImpl {
int status; int status;
IGeofenceHardwareCallback callback; IGeofenceHardwareCallback callback;
switch (msg.what) { switch (msg.what) {
case ADD_GEOFENCE:
geofenceId = msg.arg1;
callback = (IGeofenceHardwareCallback) msg.obj;
mGeofences.put(geofenceId, callback);
break;
case REMOVE_GEOFENCE:
geofenceId = msg.arg1;
mGeofences.remove(geofenceId);
break;
case ADD_GEOFENCE_CALLBACK: case ADD_GEOFENCE_CALLBACK:
geofenceId = msg.arg1; geofenceId = msg.arg1;
callback = mGeofences.get(geofenceId); synchronized (mGeofences) {
callback = mGeofences.get(geofenceId);
}
if (callback == null) return; if (callback == null) return;
try { try {
@@ -467,19 +479,25 @@ public final class GeofenceHardwareImpl {
break; break;
case REMOVE_GEOFENCE_CALLBACK: case REMOVE_GEOFENCE_CALLBACK:
geofenceId = msg.arg1; geofenceId = msg.arg1;
callback = mGeofences.get(geofenceId); synchronized (mGeofences) {
callback = mGeofences.get(geofenceId);
}
if (callback == null) return; if (callback == null) return;
try { try {
callback.onGeofenceRemove(geofenceId, msg.arg2); callback.onGeofenceRemove(geofenceId, msg.arg2);
} catch (RemoteException e) {} } catch (RemoteException e) {}
mGeofences.remove(geofenceId); synchronized (mGeofences) {
mGeofences.remove(geofenceId);
}
releaseWakeLock(); releaseWakeLock();
break; break;
case PAUSE_GEOFENCE_CALLBACK: case PAUSE_GEOFENCE_CALLBACK:
geofenceId = msg.arg1; geofenceId = msg.arg1;
callback = mGeofences.get(geofenceId); synchronized (mGeofences) {
callback = mGeofences.get(geofenceId);
}
if (callback == null) return; if (callback == null) return;
try { try {
@@ -490,7 +508,9 @@ public final class GeofenceHardwareImpl {
case RESUME_GEOFENCE_CALLBACK: case RESUME_GEOFENCE_CALLBACK:
geofenceId = msg.arg1; geofenceId = msg.arg1;
callback = mGeofences.get(geofenceId); synchronized (mGeofences) {
callback = mGeofences.get(geofenceId);
}
if (callback == null) return; if (callback == null) return;
try { try {
@@ -501,12 +521,14 @@ public final class GeofenceHardwareImpl {
case GEOFENCE_TRANSITION_CALLBACK: case GEOFENCE_TRANSITION_CALLBACK:
GeofenceTransition geofenceTransition = (GeofenceTransition)(msg.obj); GeofenceTransition geofenceTransition = (GeofenceTransition)(msg.obj);
callback = mGeofences.get(geofenceTransition.mGeofenceId); synchronized (mGeofences) {
callback = mGeofences.get(geofenceTransition.mGeofenceId);
}
if (DEBUG) Log.d(TAG, "GeofenceTransistionCallback: GPS : GeofenceId: " + if (DEBUG) Log.d(TAG, "GeofenceTransistionCallback: GPS : GeofenceId: " +
geofenceTransition.mGeofenceId + geofenceTransition.mGeofenceId +
"Transition: " + geofenceTransition.mTransition + " Transition: " + geofenceTransition.mTransition +
"Location: " + geofenceTransition.mLocation + ":" + mGeofences); " Location: " + geofenceTransition.mLocation + ":" + mGeofences);
try { try {
callback.onGeofenceTransition( callback.onGeofenceTransition(
@@ -521,12 +543,14 @@ public final class GeofenceHardwareImpl {
callback = (IGeofenceHardwareCallback) (msg.obj); callback = (IGeofenceHardwareCallback) (msg.obj);
if (DEBUG) Log.d(TAG, "Geofence callback reaped:" + callback); if (DEBUG) Log.d(TAG, "Geofence callback reaped:" + callback);
int monitoringType = msg.arg1; int monitoringType = msg.arg1;
for (int i = 0; i < mGeofences.size(); i++) { synchronized (mGeofences) {
if (mGeofences.valueAt(i).equals(callback)) { for (int i = 0; i < mGeofences.size(); i++) {
geofenceId = mGeofences.keyAt(i); if (mGeofences.valueAt(i).equals(callback)) {
removeGeofence(mGeofences.keyAt(i), monitoringType); geofenceId = mGeofences.keyAt(i);
mGeofences.remove(geofenceId); removeGeofence(mGeofences.keyAt(i), monitoringType);
} mGeofences.remove(geofenceId);
}
}
} }
} }
} }