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
IFactorialServiceImplemimplementing 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
Servicethat would be used to communicate aIFactorialServiceinstance 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, ServiceConnectionI want
MainActivityof 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
seriveConnectionis an object of service connection (I prefer not to usethisforServiceConnection). Also, your service should have the properActionset, otherwise it won't start