Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66f761c5 authored by Lifu Tang's avatar Lifu Tang
Browse files

Use callback to run binder service to avoid race

The binder interface should always be managed by ServiceWatcher, and
shouldn't be exposed to the caller. Otherwise the caller could cache an
unbound service, and could cause system crash.

Bug: 69008332
Test: build and manual test
Change-Id: I70d1fe0bace7b0fb1c3844c2c9113b1fcf95f784
parent 2dd2cbcb
Loading
Loading
Loading
Loading
+23 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -397,9 +398,29 @@ public class ServiceWatcher implements ServiceConnection {
        }
    }

    public @Nullable IBinder getBinder() {
    /**
     * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
     */
    public interface BinderRunner {
        /**
         * Runs on the retrieved binder.
         * @param binder the binder retrieved from the {@link ServiceWatcher}.
         */
        public void run(@NonNull IBinder binder);
    }

    /**
     * Retrieves the binder from {@link ServiceWatcher} and runs it.
     * @return whether a valid service exists.
     */
    public boolean runOnBinder(@NonNull BinderRunner runner) {
        synchronized (mLock) {
            return mBoundService;
            if (mBoundService == null) {
                return false;
            } else {
                runner.run(mBoundService);
                return true;
            }
        }
    }

+47 −43
Original line number Diff line number Diff line
@@ -103,11 +103,9 @@ public class ActivityRecognitionProxy {
     * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
     */
    private void bindProvider() {
        IBinder binder = mServiceWatcher.getBinder();
        if (binder == null) {
            Log.e(TAG, "Null binder found on connection.");
            return;
        }
        if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
            @Override
            public void run(IBinder binder) {
                String descriptor;
                try {
                    descriptor = binder.getInterfaceDescriptor();
@@ -116,7 +114,8 @@ public class ActivityRecognitionProxy {
                    return;
                }

        if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) {
                if (IActivityRecognitionHardwareWatcher.class.getCanonicalName()
                        .equals(descriptor)) {
                    IActivityRecognitionHardwareWatcher watcher =
                            IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
                    if (watcher == null) {
@@ -124,8 +123,8 @@ public class ActivityRecognitionProxy {
                        return;
                    }
                    if (mInstance == null) {
                // to keep backwards compatibility do not update the watcher when there is no
                // instance available, or it will cause an NPE
                        // to keep backwards compatibility do not update the watcher when there is
                        // no instance available, or it will cause an NPE
                        Log.d(TAG, "AR HW instance not available, binding will be a no-op.");
                        return;
                    }
@@ -134,7 +133,8 @@ public class ActivityRecognitionProxy {
                    } catch (RemoteException e) {
                        Log.e(TAG, "Error delivering hardware interface to watcher.", e);
                    }
        } else if (IActivityRecognitionHardwareClient.class.getCanonicalName().equals(descriptor)) {
                } else if (IActivityRecognitionHardwareClient.class.getCanonicalName()
                            .equals(descriptor)) {
                    IActivityRecognitionHardwareClient client =
                            IActivityRecognitionHardwareClient.Stub.asInterface(binder);
                    if (client == null) {
@@ -150,4 +150,8 @@ public class ActivityRecognitionProxy {
                    Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
                }
            }
        })) {
            Log.e(TAG, "Null binder found on connection.");
        }
    }
}
+12 −10
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Context;
import android.hardware.location.IFusedLocationHardware;
import android.location.IFusedProvider;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

@@ -112,17 +113,18 @@ public final class FusedProxy {
     * @param locationHardware  The FusedLocationHardware instance to use for the binding operation.
     */
    private void bindProvider(IFusedLocationHardware locationHardware) {
        IFusedProvider provider = IFusedProvider.Stub.asInterface(mServiceWatcher.getBinder());

        if (provider == null) {
            Log.e(TAG, "No instance of FusedProvider found on FusedLocationHardware connected.");
            return;
        }

        if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
            @Override
            public void run(IBinder binder) {
                IFusedProvider provider = IFusedProvider.Stub.asInterface(binder);
                try {
                    provider.onFusedLocationHardwareChange(locationHardware);
                } catch (RemoteException e) {
                    Log.e(TAG, e.toString());
                }
            }
        })) {
            Log.e(TAG, "No instance of FusedProvider found on FusedLocationHardware connected.");
        }
    }
}
+28 −22
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.location.Address;
import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

@@ -63,42 +64,47 @@ public class GeocoderProxy {
        return mServiceWatcher.start();
    }

    private IGeocodeProvider getService() {
        return IGeocodeProvider.Stub.asInterface(mServiceWatcher.getBinder());
    }

    public String getConnectedPackageName() {
        return mServiceWatcher.getBestPackageName();
    }

    public String getFromLocation(double latitude, double longitude, int maxResults,
            GeocoderParams params, List<Address> addrs) {
        IGeocodeProvider provider = getService();
        if (provider != null) {
        final String[] result = new String[] {"Service not Available"};
        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
            @Override
            public void run(IBinder binder) {
                IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
                try {
                return provider.getFromLocation(latitude, longitude, maxResults, params, addrs);
                    result[0] = provider.getFromLocation(
                            latitude, longitude, maxResults, params, addrs);
                } catch (RemoteException e) {
                    Log.w(TAG, e);
                }
            }
        return "Service not Available";
        });
        return result[0];
    }

    public String getFromLocationName(String locationName,
            double lowerLeftLatitude, double lowerLeftLongitude,
            double upperRightLatitude, double upperRightLongitude, int maxResults,
            GeocoderParams params, List<Address> addrs) {
        IGeocodeProvider provider = getService();
        if (provider != null) {
        final String[] result = new String[] {"Service not Available"};
        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
            @Override
            public void run(IBinder binder) {
                IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
                try {
                return provider.getFromLocationName(locationName, lowerLeftLatitude,
                    result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
                            lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
                            maxResults, params, addrs);
                } catch (RemoteException e) {
                    Log.w(TAG, e);
                }
            }
        return "Service not Available";
        });
        return result[0];
    }

}
+10 −8
Original line number Diff line number Diff line
@@ -116,16 +116,18 @@ public final class GeofenceProxy {
    };

    private void setGeofenceHardwareInProviderLocked() {
        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
            @Override
            public void run(IBinder binder) {
                final IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
                try {
            IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(
                      mServiceWatcher.getBinder());
            if (provider != null) {
                    provider.setGeofenceHardware(mGeofenceHardware);
            }
                } catch (RemoteException e) {
                    Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
                }
            }
        });
    }

    private void setGpsGeofenceLocked() {
        try {
Loading