bindService() in client app fails when trying to do IPC with another app

847 views Asked by At

I wanted to get some experience with android IPC using AIDL. I wanted to see if it was possible to communicate between two distinct android apps.

My problem is that invoking bindService in the second app, to communicate with the first app's FactorialService, service always fails. My first app activity MainActivity which tries to call bindService always log the fact that bindService returns false. Plus MainActivity (which implements ServiceConnection) of this second app (the client app) never gets its callback method onServiceConnected called.

So, in a first application which runs a service called FactorialService

  • I defined an
    interface, IFactorialService.aidl:

    package com.simonlbc.factorialcommon;
    
    import com.simonlbc.factorialcommon.FactorialRequest;
    import com.simonlbc.factorialcommon.FactorialResponse;
    
    interface IFactorialService {
        FactorialResponse fact(in FactorialRequest r);
    }
    

FactorialRequest contains an input number (say n). fact returns n! along with other information.

  • In the same application I created a class IFactorialServiceImplem implementing that aidl interface.

    package com.example.simonlbc.factorialservice;
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.SystemClock;
    import com.simonlbc.factorialcommon.FactorialResponse;
    import com.simonlbc.factorialcommon.FactorialRequest;
    
    public class IFactorialServiceImplem extends com.simonlbc.factorialcommon.IFactorialService.Stub {
    
        public long recursiveFact(int n) {
            if (n < 0)
                throw new IllegalArgumentException("input fa");
            if (n == 1 || n == 0)
                return 1;
            else {
                return n * recursiveFact(n-1);
            }
        }
    
        public long iterativeFact(int n) {
            long res = 1;
            for (int i = 1; i <= n; i++)
                res *= i;
            return res;
        }
        public FactorialResponse fact(FactorialRequest r) {
            long timeInMillis = SystemClock.uptimeMillis();
            long result = 0;
    
            switch(r.getChoice()) {
                case RECURSIVE:
                    result = recursiveFact(r.getInNb());
                    break;
                case ITERATIVE:
                    result = iterativeFact(r.getInNb());
            }
            timeInMillis = SystemClock.uptimeMillis() - timeInMillis;
    
            return new FactorialResponse(result, timeInMillis);
        }
    }
    
    • I then created a Service that would be used to communicate a IFactorialService instance to possible clients:

      package com.example.simonlbc.factorialservice;
      import android.app.Service;
      import android.content.Intent;
      import android.os.IBinder;
      import android.util.Log;
      import com.simonlbc.factorialcommon.IFactorialService;
      
      public class FactorialService extends Service {
      
          private IFactorialServiceImplem s = null;
          private static final String TAG = "FactorialService";
      
          @Override
          public void onCreate() {
              super.onCreate();
              s = new IFactorialServiceImplem();
              Log.d(TAG, "onCreate'd");
          }
              @Override
              public IBinder onBind(Intent intent) {
                  Log.d(TAG, "onBind()'d");
                  return this.s;
              }
      
              @Override
              public boolean onUnbind(Intent intent) {
                  Log.d(TAG, "onUnbind()'d");
                  return super.onUnbind(intent);
              }
      
              @Override
              public void onDestroy() {
                  Log.d(TAG, "onDestroy()'d");
                  s = null;
                  super.onDestroy();
              }
          }
      
      • the manifest of this first "service" app is the following:

      <application
          android:allowBackup="true"
          android:icon="@mipmap/ic_launcher"
          android:label="@string/app_name"
          android:supportsRtl="true"
          android:theme="@style/AppTheme">
      
          <service
              android:name=".FactorialService">
              <!--
              android:enabled="true"
              android:exported="true"
              android:process=":remote"
              -->
      
              <intent-filter>
                  <action android:name="com.example.simonlbc.factorialservice.FactorialService" />
              </intent-filter>
          </service>
      
          <activity android:name=".MainActivity">
              <intent-filter>
                  <action android:name="android.intent.action.MAIN" />
      
                  <category android:name="android.intent.category.LAUNCHER" />
              </intent-filter>
          </activity>
      </application>
      

    • the first app contains a Launcher activity which simply starts the service as so:

          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_service);
              curPackage = getString(R.string.packageService);
              MainActivity.this.startService(
                      new Intent()
                              .setAction(curPackage + ".FactorialService")
                              .setPackage(curPackage)
              );
          }
      


  • My second app's launcher activity is such as:

    public class MainActivity extends Activity implements View.OnClickListener, ServiceConnection

    I want MainActivity of this second app to
    communicate with the first's app IFactorialService. In onResume I try to bind with the first app's service:

       @Override
       protected void onResume() {
           super.onResume();
           Intent i = new Intent();
           i.setAction("com.example.simonlbc.factorialservice.FactorialService");
           i.setPackage("com.example.simonlbc");
           if (!super.bindService(i, this, BIND_AUTO_CREATE))
               Log.w(TAG, "Failed to bind our service!!!");
       }
    

But it seems bindService fails. Indeed everytime I pause the app and return to it, or start it. "Failed to bind our service!!!" is displayed.

Note that the two app share an Android Library module containing the definitions of the needed aidl files.

Do you see anything that would allow bindService() to work?

1

There are 1 answers

5
Ankur Aggarwal On BEST ANSWER

Why are you using super.bindservice() ? Instead, can you try this getApplicationContext().bindservice()

Also, if this does not work either, try the following modification of your code:

   Intent i = new Intent("com.example.simonlbc.factorialservice.FactorialService");
   if(getApplicationContext().startService(i) != null){
       if (!getApplicationContext().bindService(i, serviceConnection, 0))
           Log.w(TAG, "Failed to bind our service!!!");
   }

where seriveConnection is an object of service connection (I prefer not to use this for ServiceConnection ). Also, your service should have the proper Action set, otherwise it won't start