Reputation: 641
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();
}
}
<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?
Upvotes: 0
Views: 859
Reputation: 2220
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
Upvotes: 1