diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 4834ce0da9b31..3479e18b97c53 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -67,6 +67,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.IInterface; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -109,6 +110,7 @@ import com.android.server.location.LocationRequestStatistics.PackageProviderKey; import com.android.server.location.LocationRequestStatistics.PackageStatistics; import com.android.server.location.MockProvider; import com.android.server.location.PassiveProvider; +import com.android.server.location.RemoteListenerHelper; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -121,6 +123,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; +import java.util.function.Consumer; +import java.util.function.Function; /** * The service class that manages LocationProviders and issues location @@ -225,11 +229,14 @@ public class LocationManagerService extends ILocationManager.Stub { private final ArraySet mIgnoreSettingsPackageWhitelist = new ArraySet<>(); @GuardedBy("mLock") - private final ArrayMap mGnssMeasurementsListeners = new ArrayMap<>(); - + private final ArrayMap> + mGnssMeasurementsListeners = new ArrayMap<>(); @GuardedBy("mLock") - private final ArrayMap + private final ArrayMap> mGnssNavigationMessageListeners = new ArrayMap<>(); + @GuardedBy("mLock") + private final ArrayMap> + mGnssStatusListeners = new ArrayMap<>(); // current active user on the device - other users are denied location data private int mCurrentUserId = UserHandle.USER_SYSTEM; @@ -243,7 +250,7 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") private IBatchedLocationCallback mGnssBatchingCallback; @GuardedBy("mLock") - private LinkedCallback mGnssBatchingDeathCallback; + private LinkedListener mGnssBatchingDeathCallback; @GuardedBy("mLock") private boolean mGnssBatchingInProgress = false; @@ -485,7 +492,7 @@ public class LocationManagerService extends ILocationManager.Stub { && record.mIsForegroundUid != foreground) { if (D) { Log.d(TAG, "request from uid " + uid + " is now " - + (foreground ? "foreground" : "background)")); + + foregroundAsString(foreground)); } record.updateForeground(foreground); @@ -499,44 +506,48 @@ public class LocationManagerService extends ILocationManager.Stub { applyRequirementsLocked(provider); } - for (Entry entry : mGnssMeasurementsListeners.entrySet()) { - CallerIdentity callerIdentity = entry.getValue(); - if (callerIdentity.mUid == uid) { - if (D) { - Log.d(TAG, "gnss measurements listener from uid " + uid - + " is now " + (foreground ? "foreground" : "background)")); - } - if (foreground || isThrottlingExemptLocked(entry.getValue())) { - mGnssMeasurementsProvider.addListener( - IGnssMeasurementsListener.Stub.asInterface(entry.getKey()), - callerIdentity); - } else { - mGnssMeasurementsProvider.removeListener( - IGnssMeasurementsListener.Stub.asInterface(entry.getKey())); - } - } - } + updateGnssDataProviderOnUidImportanceChangedLocked(mGnssMeasurementsListeners, + mGnssMeasurementsProvider, IGnssMeasurementsListener.Stub::asInterface, + uid, foreground); - for (Entry entry : mGnssNavigationMessageListeners.entrySet()) { - CallerIdentity callerIdentity = entry.getValue(); - if (callerIdentity.mUid == uid) { - if (D) { - Log.d(TAG, "gnss navigation message listener from uid " - + uid + " is now " - + (foreground ? "foreground" : "background)")); - } - if (foreground || isThrottlingExemptLocked(entry.getValue())) { - mGnssNavigationMessageProvider.addListener( - IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()), - callerIdentity); - } else { - mGnssNavigationMessageProvider.removeListener( - IGnssNavigationMessageListener.Stub.asInterface(entry.getKey())); - } + updateGnssDataProviderOnUidImportanceChangedLocked(mGnssNavigationMessageListeners, + mGnssNavigationMessageProvider, IGnssNavigationMessageListener.Stub::asInterface, + uid, foreground); + + updateGnssDataProviderOnUidImportanceChangedLocked(mGnssStatusListeners, + mGnssStatusProvider, IGnssStatusListener.Stub::asInterface, uid, foreground); + } + + @GuardedBy("mLock") + private void updateGnssDataProviderOnUidImportanceChangedLocked( + ArrayMap gnssDataListeners, + RemoteListenerHelper gnssDataProvider, + Function mapBinderToListener, int uid, boolean foreground) { + for (Entry entry : gnssDataListeners.entrySet()) { + LinkedListenerBase linkedListener = entry.getValue(); + CallerIdentity callerIdentity = linkedListener.mCallerIdentity; + if (callerIdentity.mUid != uid) { + continue; + } + + if (D) { + Log.d(TAG, linkedListener.mListenerName + " from uid " + + uid + " is now " + foregroundAsString(foreground)); + } + + TListener listener = mapBinderToListener.apply(entry.getKey()); + if (foreground || isThrottlingExemptLocked(callerIdentity)) { + gnssDataProvider.addListener(listener, callerIdentity); + } else { + gnssDataProvider.removeListener(listener); } } } + private static String foregroundAsString(boolean foreground) { + return foreground ? "foreground" : "background"; + } + private static boolean isImportanceForeground(int importance) { return importance <= FOREGROUND_IMPORTANCE_CUTOFF; } @@ -1218,9 +1229,8 @@ public class LocationManagerService extends ILocationManager.Stub { * A wrapper class holding either an ILocationListener or a PendingIntent to receive * location updates. */ - private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { + private final class Receiver extends LinkedListenerBase implements PendingIntent.OnFinished { private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000; - final CallerIdentity mCallerIdentity; private final int mAllowedResolutionLevel; // resolution level allowed to receiver private final ILocationListener mListener; @@ -1240,6 +1250,7 @@ public class LocationManagerService extends ILocationManager.Stub { private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) { + super(new CallerIdentity(uid, pid, packageName), "LocationListener"); mListener = listener; mPendingIntent = intent; if (listener != null) { @@ -1248,7 +1259,6 @@ public class LocationManagerService extends ILocationManager.Stub { mKey = intent; } mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid); - mCallerIdentity = new CallerIdentity(uid, pid, packageName); if (workSource != null && workSource.isEmpty()) { workSource = null; } @@ -1486,7 +1496,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void binderDied() { - if (D) Log.d(TAG, "Location listener died"); + if (D) Log.d(TAG, "Remote " + mListenerName + " died."); synchronized (mLock) { removeUpdatesLocked(this); @@ -1617,53 +1627,59 @@ public class LocationManagerService extends ILocationManager.Stub { return false; } + CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), + Binder.getCallingPid(), packageName); synchronized (mLock) { mGnssBatchingCallback = callback; - mGnssBatchingDeathCallback = new LinkedCallback(callback); - try { - callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */); - } catch (RemoteException e) { - // if the remote process registering the listener is already dead, just swallow the - // exception and return - Log.e(TAG, "Remote listener already died.", e); + mGnssBatchingDeathCallback = new LinkedListener<>(callback, + "BatchedLocationCallback", callerIdentity, + (IBatchedLocationCallback listener) -> { + stopGnssBatch(); + removeGnssBatchingCallback(); + }); + if (!linkToListenerDeathNotificationLocked(callback.asBinder(), + mGnssBatchingDeathCallback)) { return false; } - return true; } } - private class LinkedCallback implements IBinder.DeathRecipient { - private final IBatchedLocationCallback mCallback; + private abstract static class LinkedListenerBase implements IBinder.DeathRecipient { + protected final CallerIdentity mCallerIdentity; + protected final String mListenerName; - private LinkedCallback(@NonNull IBatchedLocationCallback callback) { - mCallback = callback; + private LinkedListenerBase(@NonNull CallerIdentity callerIdentity, + @NonNull String listenerName) { + mCallerIdentity = callerIdentity; + mListenerName = listenerName; } + } - @NonNull - public IBatchedLocationCallback getUnderlyingListener() { - return mCallback; + private static class LinkedListener extends LinkedListenerBase { + private final TListener mListener; + private final Consumer mBinderDeathCallback; + + private LinkedListener(@NonNull TListener listener, String listenerName, + @NonNull CallerIdentity callerIdentity, + @NonNull Consumer binderDeathCallback) { + super(callerIdentity, listenerName); + mListener = listener; + mBinderDeathCallback = binderDeathCallback; } @Override public void binderDied() { - Log.d(TAG, "Remote Batching Callback died: " + mCallback); - stopGnssBatch(); - removeGnssBatchingCallback(); + if (D) Log.d(TAG, "Remote " + mListenerName + " died."); + mBinderDeathCallback.accept(mListener); } } @Override public void removeGnssBatchingCallback() { synchronized (mLock) { - try { - mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback, - 0 /* flags */); - } catch (NoSuchElementException e) { - // if the death callback isn't connected (it should be...), log error, swallow the - // exception and return - Log.e(TAG, "Couldn't unlink death callback.", e); - } + unlinkFromListenerDeathNotificationLocked(mGnssBatchingCallback.asBinder(), + mGnssBatchingDeathCallback); mGnssBatchingCallback = null; mGnssBatchingDeathCallback = null; } @@ -2264,10 +2280,8 @@ public class LocationManagerService extends ILocationManager.Stub { if (receiver == null) { receiver = new Receiver(listener, null, pid, uid, packageName, workSource, hideFromAppOps); - try { - receiver.getListener().asBinder().linkToDeath(receiver, 0); - } catch (RemoteException e) { - Slog.e(TAG, "linkToDeath failed:", e); + if (!linkToListenerDeathNotificationLocked(receiver.getListener().asBinder(), + receiver)) { return null; } mReceivers.put(binder, receiver); @@ -2482,7 +2496,8 @@ public class LocationManagerService extends ILocationManager.Stub { if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver))); if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { - receiver.getListener().asBinder().unlinkToDeath(receiver, 0); + unlinkFromListenerDeathNotificationLocked(receiver.getListener().asBinder(), + receiver); receiver.clearPendingBroadcastsLocked(); } @@ -2694,18 +2709,52 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) { + public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) { if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) { return false; } - return mGnssStatusProvider.addListener(callback, new CallerIdentity(Binder.getCallingUid(), - Binder.getCallingPid(), packageName)); + CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), + Binder.getCallingPid(), packageName); + LinkedListener linkedListener = new LinkedListener<>(listener, + "GnssStatusListener", callerIdentity, this::unregisterGnssStatusCallback); + IBinder binder = listener.asBinder(); + synchronized (mLock) { + if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) { + return false; + } + + mGnssStatusListeners.put(binder, linkedListener); + long identity = Binder.clearCallingIdentity(); + try { + if (isThrottlingExemptLocked(callerIdentity) + || isImportanceForeground( + mActivityManager.getPackageImportance(packageName))) { + mGnssStatusProvider.addListener(listener, callerIdentity); + } + return true; + } finally { + Binder.restoreCallingIdentity(identity); + } + } } @Override - public void unregisterGnssStatusCallback(IGnssStatusListener callback) { - mGnssStatusProvider.removeListener(callback); + public void unregisterGnssStatusCallback(IGnssStatusListener listener) { + if (mGnssStatusProvider == null) { + return; + } + + IBinder binder = listener.asBinder(); + synchronized (mLock) { + LinkedListener linkedListener = + mGnssStatusListeners.remove(binder); + if (linkedListener == null) { + return; + } + unlinkFromListenerDeathNotificationLocked(binder, linkedListener); + mGnssStatusProvider.removeListener(listener); + } } @Override @@ -2715,22 +2764,75 @@ public class LocationManagerService extends ILocationManager.Stub { return false; } + CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), + Binder.getCallingPid(), packageName); + LinkedListener linkedListener = new LinkedListener<>(listener, + "GnssMeasurementsListener", callerIdentity, this::removeGnssMeasurementsListener); + IBinder binder = listener.asBinder(); synchronized (mLock) { - CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), - Binder.getCallingPid(), packageName); - mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity); + if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) { + return false; + } + + mGnssMeasurementsListeners.put(binder, linkedListener); long identity = Binder.clearCallingIdentity(); try { if (isThrottlingExemptLocked(callerIdentity) || isImportanceForeground( mActivityManager.getPackageImportance(packageName))) { - return mGnssMeasurementsProvider.addListener(listener, callerIdentity); + mGnssMeasurementsProvider.addListener(listener, callerIdentity); } + return true; } finally { Binder.restoreCallingIdentity(identity); } + } + } + @Override + public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) { + if (mGnssMeasurementsProvider == null) { + return; + } + + IBinder binder = listener.asBinder(); + synchronized (mLock) { + LinkedListener linkedListener = + mGnssMeasurementsListeners.remove(binder); + if (linkedListener == null) { + return; + } + unlinkFromListenerDeathNotificationLocked(binder, linkedListener); + mGnssMeasurementsProvider.removeListener(listener); + } + } + + + private boolean linkToListenerDeathNotificationLocked(IBinder binder, + LinkedListenerBase linkedListener) { + try { + binder.linkToDeath(linkedListener, 0 /* flags */); return true; + } catch (RemoteException e) { + // if the remote process registering the listener is already dead, just swallow the + // exception and return + Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.", + e); + return false; + } + } + + private boolean unlinkFromListenerDeathNotificationLocked(IBinder binder, + LinkedListenerBase linkedListener) { + try { + binder.unlinkToDeath(linkedListener, 0 /* flags */); + return true; + } catch (NoSuchElementException e) { + // if the death callback isn't connected (it should be...), log error, + // swallow the exception and return + Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.", + e); + return false; } } @@ -2758,53 +2860,54 @@ public class LocationManagerService extends ILocationManager.Stub { return mGnssMeasurementsProvider.getGnssCapabilities(); } - @Override - public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) { - if (mGnssMeasurementsProvider == null) { - return; - } - - synchronized (mLock) { - mGnssMeasurementsListeners.remove(listener.asBinder()); - mGnssMeasurementsProvider.removeListener(listener); - } - } - @Override public boolean addGnssNavigationMessageListener( - IGnssNavigationMessageListener listener, - String packageName) { + IGnssNavigationMessageListener listener, String packageName) { if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) { return false; } + CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), + Binder.getCallingPid(), packageName); + LinkedListener linkedListener = + new LinkedListener<>(listener, "GnssNavigationMessageListener", callerIdentity, + this::removeGnssNavigationMessageListener); + IBinder binder = listener.asBinder(); synchronized (mLock) { - CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), - Binder.getCallingPid(), packageName); + if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) { + return false; + } - mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity); + mGnssNavigationMessageListeners.put(binder, linkedListener); long identity = Binder.clearCallingIdentity(); try { if (isThrottlingExemptLocked(callerIdentity) || isImportanceForeground( mActivityManager.getPackageImportance(packageName))) { - return mGnssNavigationMessageProvider.addListener(listener, callerIdentity); + mGnssNavigationMessageProvider.addListener(listener, callerIdentity); } + return true; } finally { Binder.restoreCallingIdentity(identity); } - - return true; } } @Override public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) { - if (mGnssNavigationMessageProvider != null) { - synchronized (mLock) { - mGnssNavigationMessageListeners.remove(listener.asBinder()); - mGnssNavigationMessageProvider.removeListener(listener); + if (mGnssNavigationMessageProvider == null) { + return; + } + + IBinder binder = listener.asBinder(); + synchronized (mLock) { + LinkedListener linkedListener = + mGnssNavigationMessageListeners.remove(binder); + if (linkedListener == null) { + return; } + unlinkFromListenerDeathNotificationLocked(binder, linkedListener); + mGnssNavigationMessageProvider.removeListener(listener); } } @@ -3368,18 +3471,14 @@ public class LocationManagerService extends ILocationManager.Stub { pw.println(" " + record); } } + pw.println(" Active GnssMeasurement Listeners:"); - for (CallerIdentity callerIdentity : mGnssMeasurementsListeners.values()) { - pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " " - + callerIdentity.mPackageName + ": " - + isThrottlingExemptLocked(callerIdentity)); - } + dumpGnssDataListenersLocked(pw, mGnssMeasurementsListeners); pw.println(" Active GnssNavigationMessage Listeners:"); - for (CallerIdentity callerIdentity : mGnssNavigationMessageListeners.values()) { - pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " " - + callerIdentity.mPackageName + ": " - + isThrottlingExemptLocked(callerIdentity)); - } + dumpGnssDataListenersLocked(pw, mGnssNavigationMessageListeners); + pw.println(" Active GnssStatus Listeners:"); + dumpGnssDataListenersLocked(pw, mGnssStatusListeners); + pw.println(" Historical Records by Provider:"); for (Map.Entry entry : mRequestStatistics.statistics.entrySet()) { @@ -3432,4 +3531,15 @@ public class LocationManagerService extends ILocationManager.Stub { } } } + + @GuardedBy("mLock") + private void dumpGnssDataListenersLocked(PrintWriter pw, + ArrayMap gnssDataListeners) { + for (LinkedListenerBase listener : gnssDataListeners.values()) { + CallerIdentity callerIdentity = listener.mCallerIdentity; + pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " " + + callerIdentity.mPackageName + ": " + + isThrottlingExemptLocked(callerIdentity)); + } + } } diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java index f03c99b0272e5..aa8a25a363331 100644 --- a/services/core/java/com/android/server/location/RemoteListenerHelper.java +++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java @@ -31,9 +31,11 @@ import java.util.HashMap; import java.util.Map; /** - * A helper class, that handles operations in remote listeners, and tracks for remote process death. + * A helper class that handles operations in remote listeners. + * + * @param the type of GNSS data listener. */ -abstract class RemoteListenerHelper { +public abstract class RemoteListenerHelper { protected static final int RESULT_SUCCESS = 0; protected static final int RESULT_NOT_AVAILABLE = 1; @@ -46,7 +48,7 @@ abstract class RemoteListenerHelper { protected final Handler mHandler; private final String mTag; - private final Map mListenerMap = new HashMap<>(); + private final Map mListenerMap = new HashMap<>(); protected final Context mContext; protected final AppOpsManager mAppOps; @@ -71,24 +73,21 @@ abstract class RemoteListenerHelper { return mIsRegistered; } - public boolean addListener(@NonNull TListener listener, CallerIdentity callerIdentity) { + /** + * Adds GNSS data listener {@code listener} with caller identify {@code callerIdentify}. + */ + public void addListener(@NonNull TListener listener, CallerIdentity callerIdentity) { Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener."); IBinder binder = listener.asBinder(); - LinkedListener deathListener = new LinkedListener(listener, callerIdentity); synchronized (mListenerMap) { if (mListenerMap.containsKey(binder)) { // listener already added - return true; + return; } - try { - binder.linkToDeath(deathListener, 0 /* flags */); - } catch (RemoteException e) { - // if the remote process registering the listener is already death, just swallow the - // exception and return - Log.v(mTag, "Remote listener already died.", e); - return false; - } - mListenerMap.put(binder, deathListener); + + IdentifiedListener identifiedListener = new IdentifiedListener(listener, + callerIdentity); + mListenerMap.put(binder, identifiedListener); // update statuses we already know about, starting from the ones that will never change int result; @@ -107,26 +106,23 @@ abstract class RemoteListenerHelper { } else { // at this point if the supported flag is not set, the notification will be sent // asynchronously in the future - return true; + return; } - post(deathListener, getHandlerOperation(result)); + post(identifiedListener, getHandlerOperation(result)); } - return true; } + /** + * Remove GNSS data listener {@code listener}. + */ public void removeListener(@NonNull TListener listener) { Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener."); - IBinder binder = listener.asBinder(); - LinkedListener linkedListener; synchronized (mListenerMap) { - linkedListener = mListenerMap.remove(binder); + mListenerMap.remove(listener.asBinder()); if (mListenerMap.isEmpty()) { tryUnregister(); } } - if (linkedListener != null) { - binder.unlinkToDeath(linkedListener, 0 /* flags */); - } } protected abstract boolean isAvailableInPlatform(); @@ -198,14 +194,15 @@ abstract class RemoteListenerHelper { } private void foreachUnsafe(ListenerOperation operation) { - for (LinkedListener linkedListener : mListenerMap.values()) { - post(linkedListener, operation); + for (IdentifiedListener identifiedListener : mListenerMap.values()) { + post(identifiedListener, operation); } } - private void post(LinkedListener linkedListener, ListenerOperation operation) { + private void post(IdentifiedListener identifiedListener, + ListenerOperation operation) { if (operation != null) { - mHandler.post(new HandlerRunnable(linkedListener, operation)); + mHandler.post(new HandlerRunnable(identifiedListener, operation)); } } @@ -259,35 +256,31 @@ abstract class RemoteListenerHelper { return RESULT_SUCCESS; } - private class LinkedListener implements IBinder.DeathRecipient { + private class IdentifiedListener { private final TListener mListener; private final CallerIdentity mCallerIdentity; - LinkedListener(@NonNull TListener listener, CallerIdentity callerIdentity) { + private IdentifiedListener(@NonNull TListener listener, CallerIdentity callerIdentity) { mListener = listener; mCallerIdentity = callerIdentity; } - - @Override - public void binderDied() { - Log.d(mTag, "Remote Listener died: " + mListener); - removeListener(mListener); - } } private class HandlerRunnable implements Runnable { - private final LinkedListener mLinkedListener; + private final IdentifiedListener mIdentifiedListener; private final ListenerOperation mOperation; - HandlerRunnable(LinkedListener linkedListener, ListenerOperation operation) { - mLinkedListener = linkedListener; + private HandlerRunnable(IdentifiedListener identifiedListener, + ListenerOperation operation) { + mIdentifiedListener = identifiedListener; mOperation = operation; } @Override public void run() { try { - mOperation.execute(mLinkedListener.mListener, mLinkedListener.mCallerIdentity); + mOperation.execute(mIdentifiedListener.mListener, + mIdentifiedListener.mCallerIdentity); } catch (RemoteException e) { Log.v(mTag, "Error in monitored listener.", e); }