I'm attempting to create a program in Android which communicates rapidly with a remote service (~40,000/sec), however all Android IPC seems to fall short of being able to accomplish this task. My first attempt involved a standard Messenger system which was unable to do more then ~2,000/second and equally bad was that it seemed punctuated with intermittent lag.
MainActivity (Test with Messengers)
public class MainActivity extends Activity implements ServiceConnection{
Messenger mServiceMessenger;
Messenger mClientMessenger = new Messenger(new ClientHandler());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,TestService.class);
bindService(intent,this, Context.BIND_AUTO_CREATE);
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mServiceMessenger = new Messenger(service);
Message m = Message.obtain();
m.replyTo = mClientMessenger;
try {
mServiceMessenger.send(m);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {}
public class ClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Log.d("Spam","Message Received");
}
}
}
RemoteService (Test with Messengers)
public class TestService extends Service {
private Messenger mServiceMessenger = new Messenger(new ServiceHandler());
private Messenger mClientMessenger;
private Random r = new Random();
public TestService() {
super();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return mServiceMessenger.getBinder();
}
public void initSpam(){
for(int i=0;i<10;i++) {
TimerTask task = new TimerTask() {
@Override
public void run() {
Bundle b = new Bundle();
b.putInt("INT",r.nextInt());
b.putLong("LONG",r.nextLong());
b.putBoolean("BOOL",r.nextBoolean());
b.putFloat("FLOAT",r.nextFloat());
b.putDouble("DOUBLE",r.nextDouble());
b.putString("STRING",String.valueOf(r.nextInt()));
Message msg = Message.obtain();
msg.setData(b);
try {
mClientMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task,1,1);
}
}
public class ServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
mClientMessenger = msg.replyTo;
initBarrage();
}
}
}
The second attempt was done with AIDL. Although this also implements Binders for IPC, I assumed had significantly less overhead. However, AIDL proved to not be significantly more efficient then Messengers and it also did not solved the issue with stuttering.
MainActivity (Test with AIDL)
public class MainActivity extends Activity implements ServiceConnection{
IRemoteService mService;
TextView countTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,TestService.class);
bindService(intent,this, Context.BIND_AUTO_CREATE);
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IRemoteService.Stub.asInterface(service);
try {
mService.registerCallback(mClientBinder);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {}
public final IServiceAidlCallback.Stub mClientBinder = new IServiceAidlCallback.Stub(){
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString){
Log.d("Spam","Callback Received");
}
};
}
RemoteService (Test with AIDL)
public class TestService extends Service {
private Random r = new Random();
private IServiceAidlCallback mClientCallback;
public TestService() {
super();
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public final IRemoteService.Stub mBinder = new IRemoteService.Stub(){
public void registerCallback(IBinder callback){
mClientCallback = IServiceAidlCallback.Stub.asInterface(callback);
initSpam();
}
};
public void initSpam(){
for(int i=0;i<10;i++) {
TimerTask task = new TimerTask() {
@Override
public void run() {
try {
mClientCallback.basicTypes(
r.nextInt(),
r.nextLong(),
r.nextBoolean(),
r.nextFloat(),
r.nextDouble(),
String.valueOf(r.nextInt()));
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task,1,1);
}
}
}
Am I doing something wrong in either of these cases which would prevent me from getting above ~5,000/second? or is there another system for Android IPC that I was not aware of?
The Android Interface Definition Language (AIDL) is similar to other IDLs you might have worked with. It allows you to define the programming interface that both the client and service agree upon in order to communicate with each other using interprocess communication (IPC).
The Android Interface Definition Language (AIDL) is a tool that lets users abstract away IPC. Given an interface (specified in a . aidl file), various build systems use the aidl binary to construct C++ or Java bindings so that this interface can be used across processes, regardless of the runtime or bitness there.
do something like that:
MainActivity
// use it for writing: stream.write(byte[])
// (make sure to write as biggest data chunks as possible)
// or wrap it around some other streams like DataOutputStream
private OutputStream stream;
// ServiceConnection implementation
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
stream = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);
Parcel data = Parcel.obtain();
FileDescriptor readFileDescriptor = pipe[0].getFileDescriptor();
data.writeFileDescriptor(readFileDescriptor);
service.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "onServiceConnected " + stream);
}
RemoteService
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind ");
return binder;
}
IBinder binder = new Binder() {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
ParcelFileDescriptor pfd = data.readFileDescriptor();
final InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
// do something with a 'stream', start a new Thread for example and read data in a loop
...
...
return true;
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With