Handle CallServiceProvider crash

Change-Id: Icd2d108a09d6094038c413cf77029f45d251ada5
diff --git a/src/com/android/telecomm/CallServiceProviderWrapper.java b/src/com/android/telecomm/CallServiceProviderWrapper.java
index 1a3b3e1..22b8187 100644
--- a/src/com/android/telecomm/CallServiceProviderWrapper.java
+++ b/src/com/android/telecomm/CallServiceProviderWrapper.java
@@ -17,31 +17,55 @@
 package com.android.telecomm;
 
 import android.content.ComponentName;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.telecomm.CallServiceDescriptor;
 import android.telecomm.TelecommConstants;
 
 import com.android.internal.telecomm.ICallServiceLookupResponse;
 import com.android.internal.telecomm.ICallServiceProvider;
 
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 /**
  * Wrapper for {@link ICallServiceProvider}s, handles binding to {@link ICallServiceProvider} and
  * keeps track of when the object can safely be unbound. Other classes should not use
  * {@link ICallServiceProvider} directly and instead should use this class to invoke methods of
  * {@link ICallServiceProvider}.
- * TODO(santoscordon): Keep track of when the service can be safely unbound.
  */
 final class CallServiceProviderWrapper extends ServiceBinder<ICallServiceProvider> {
-    /**
-     * The service action used to bind to ICallServiceProvider implementations.
-     * TODO(santoscordon): Move this to TelecommConstants.
-     */
-    static final String CALL_SERVICE_PROVIDER_ACTION = ICallServiceProvider.class.getName();
+    interface LookupResponse {
+        void setCallServiceDescriptors(List<CallServiceDescriptor> descriptors);
+    }
+
+    private class LookupResponseWrapper extends ICallServiceLookupResponse.Stub {
+        private final LookupResponse mResponse;
+
+        LookupResponseWrapper(LookupResponse response) {
+            mResponse = response;
+        }
+
+        @Override
+        public void setCallServiceDescriptors(final List<CallServiceDescriptor> descriptors) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (mLookupResponses.remove(mResponse)) {
+                        mResponse.setCallServiceDescriptors(descriptors);
+                    }
+                }
+            });
+        }
+    };
 
     /** The actual service implementation. */
     private ICallServiceProvider mServiceInterface;
-
-    private Binder mBinder = new Binder();
+    private final Binder mBinder = new Binder();
+    private Set<LookupResponse> mLookupResponses = new HashSet<LookupResponse>();
+    private final Handler mHandler = new Handler();
 
     /**
      * Creates a call-service provider for the specified component.
@@ -53,30 +77,30 @@
     }
 
     /**
-     * initiates a call-service lookup cycle, see {@link ICallServiceProvider#lookupCallServices}.
-     * Upon failure, the specified error callback is invoked.  Can be invoked even when the call
-     * service is unbound.
+     * Initiates a call-service lookup cycle, see {@link ICallServiceProvider#lookupCallServices}.
+     * Can be invoked even when the call service is unbound.
      *
      * @param response The response object via which to return the relevant call-service
      *     implementations, if any.
-     * @param errorCallback The callback to invoke upon failure.
      */
-    void lookupCallServices(
-            final ICallServiceLookupResponse response,
-            final Runnable errorCallback) {
-
+    void lookupCallServices(final LookupResponse response) {
+        mLookupResponses.add(response);
         BindCallback callback = new BindCallback() {
-            @Override public void onSuccess() {
+            @Override
+            public void onSuccess() {
                 if (isServiceValid("lookupCallServices")) {
                     try {
-                        mServiceInterface.lookupCallServices(response);
+                        mServiceInterface.lookupCallServices(new LookupResponseWrapper(response));
                     } catch (RemoteException e) {
-                        Log.e(CallServiceProviderWrapper.this, e, "Failed to lookupCallServices.");
                     }
                 }
             }
-            @Override public void onFailure() {
-                errorCallback.run();
+
+            @Override
+            public void onFailure() {
+                if (mLookupResponses.remove(response)) {
+                    response.setCallServiceDescriptors(null);
+                }
             }
         };
 
@@ -85,6 +109,16 @@
 
     /** {@inheritDoc} */
     @Override protected void setServiceInterface(IBinder binder) {
-        mServiceInterface = ICallServiceProvider.Stub.asInterface(binder);
+        if (binder == null) {
+            mServiceInterface = null;
+
+            Set<LookupResponse> responses = mLookupResponses;
+            mLookupResponses = new HashSet<LookupResponse>();
+            for (LookupResponse response : responses) {
+                response.setCallServiceDescriptors(null);
+            }
+        } else {
+            mServiceInterface = ICallServiceProvider.Stub.asInterface(binder);
+        }
     }
 }
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index e1feb0f..cdef130 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -21,7 +21,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.os.Handler;
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.TelecommConstants;
 
@@ -100,29 +99,12 @@
         private void queryProviderForCallServices(final ComponentName providerName) {
             final CallServiceProviderWrapper provider = new CallServiceProviderWrapper(
                     providerName);
-
-            ICallServiceLookupResponse response = new ICallServiceLookupResponse.Stub() {
-                    @Override
-                public void setCallServiceDescriptors(
-                        final List<CallServiceDescriptor> callServiceDescriptors) {
-
-                    mHandler.post(new Runnable() {
-                            @Override
-                        public void run() {
-                            processCallServices(provider, Sets.newHashSet(callServiceDescriptors));
-                        }
-                    });
+            provider.lookupCallServices(new CallServiceProviderWrapper.LookupResponse() {
+                @Override
+                public void setCallServiceDescriptors(List<CallServiceDescriptor> descriptors) {
+                    processCallServices(provider, descriptors);
                 }
-            };
-
-            Runnable errorCallback = new Runnable() {
-                    @Override
-                public void run() {
-                    processCallServices(provider, null);
-                }
-            };
-
-            provider.lookupCallServices(response, errorCallback);
+            });
         }
 
         /**
@@ -133,17 +115,17 @@
          */
         private void processCallServices(
                 CallServiceProviderWrapper provider,
-                Set<CallServiceDescriptor> callServiceDescriptors) {
+                List<CallServiceDescriptor> descriptors) {
 
             // Descriptor lookup finished, we no longer need the provider.
             provider.unbind();
 
             ComponentName providerName = provider.getComponentName();
             if (mOutstandingProviders.remove(providerName)) {
-                if (callServiceDescriptors != null) {
+                if (descriptors != null) {
                     // Add all the connection services from this provider to the connection-service
                     // cache.
-                    for (CallServiceDescriptor descriptor : callServiceDescriptors) {
+                    for (CallServiceDescriptor descriptor : descriptors) {
                         mServices.add(getService(descriptor.getServiceComponent(), descriptor));
                     }
                 }
@@ -162,7 +144,6 @@
     }
 
     private final IncomingCallsManager mIncomingCallsManager;
-    private final Handler mHandler = new Handler();
 
     /** Persists specified parameters. */
     CallServiceRepository(IncomingCallsManager incomingCallsManager) {