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 aIFactorialService
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 appIFactorialService
. 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?
Why are you using
super.bindservice()
? Instead, can you try thisgetApplicationContext().bindservice()
Also, if this does not work either, try the following modification of your code:
where
seriveConnection
is an object of service connection (I prefer not to usethis
forServiceConnection
). Also, your service should have the properAction
set, otherwise it won't start