1

I have two apps: One is called my-app.apk, the other my-service.apk. The service app just defines a single Android Service, which can be bound by the primary app to execute some methods. This is done using Androids AIDL interface, and it works great - so far.

Now I want to change the interface of the service, and I am wondering what I have to watch out for. I changed the file IRemote.aidl of my-service.apk to the following:

package com.example.myservice;
interface IRemote {
  void printHello();
  void print(int i);
}

And just out of curiosity I changed the IRemote.aidl of my-app.apk to the following (note the differences!):

package com.example.myservice;
interface IRemote {
  void printHello();
  void printYeahThisHasADifferentNameAndParam(String s);
}

Now I got a completely unexpected result: The call to

printYeahThisHasADifferentNameAndParam("hello world");

from my application resulted in the log output "11". Why??

  1. I would not have expected a SecurityException at the bindService() call, although this would be adequate in a situation with completely different interfaces.
  2. What I would have expected would have been a RemoteException when executing the call, telling me that the method is not available.
  3. What I didn't expect entirely was that it will just call a different method with different data as parameters. Although I can understand it from a low-level point of view. Maybe they did it to ensure this interface is performant...

So here are my questions:

  1. What is the best upgrade-strategy? Simply do not delete/alter old methods and order?
  2. I noticed when my-service.apk is upgraded (re-installed) the service gets lost for my-app.apk. Normally the service gets re-scheduled by the system, which it typically does on crashes. How do I ensure my-app.apk aquires the service again? Watch out for newly installed packages?

Thank you in advance for your help! :-)

Cheers, Marc

Onik
  • 19,396
  • 14
  • 68
  • 91
mreichelt
  • 12,359
  • 6
  • 56
  • 70
  • 1: How many aidl files have you got? Sorry but I didn't understand. 2: What IDE are you using? Anyway, when you change an aidl file, you could simply clean the aidl project and re-compile service and app projects. If you push the service to your device, it gets started when you bind to it (You must use the falg BIND_AUTO_CREATE) – edoardotognoni May 29 '13 at 14:52
  • I only have one AIDL file, but of course it must be duplicated into both the project where the service is defined *and* in the project where the service is used. And because the code ends up auto-generated in Java, then compiled into the 2 APKs, it can happen that you have two apps *A* and *B* where the interface differs. It's not a problem of the IDE at all, and I am already using BIND_AUTO_CREATE. – mreichelt May 29 '13 at 14:57
  • Ok now it's clear. I suggest you one thing: Create a new project where there is only 1 AIDL file. You reference this project in both your service and app projects. So you get rid of all files differences. Anyway, if there is some AIDL problems, Android doesn't raise exceptions, instead there could be some mismatch in method calls (different return values,strange behaviours,...) – edoardotognoni May 29 '13 at 15:00
  • Still, if I make changes to this AIDL file and B gets upgraded, A might still be using the old interface - until it gets upgraded, too. So in the end there are A, A* and B (A* is the app with the old interface). So only having one file does not change the problem I have. Let's make this more clear: The user has installed both *my-app.apk* and *my-service.apk*. Now he upgraded *my-service.apk*, but he doesn't touch *my-app.apk* at all (maybe only upgrades it after a month). – mreichelt May 29 '13 at 15:09
  • Yes that's right. When you change the AIDL you must upgrade both the applications. I don't know if there is a way to solve this "problem". But I don't see it like a problem. Yes, it should raise exceptions if the AIDL is different, that's the only thing that could be managed in a better way – edoardotognoni May 29 '13 at 15:12

1 Answers1

4

If you take a look at the code generated by the AIDL compiler, you will see that RPC via Binder calls methods by sequential number. Every method in the interface gets number assigned, like:

       SIZE = ::android::IBinder::FIRST_CALL_TRANSACTION + 0,
       SETSIZE = ::android::IBinder::FIRST_CALL_TRANSACTION + 1,
       READ = ::android::IBinder::FIRST_CALL_TRANSACTION + 2,
       WRITE = ::android::IBinder::FIRST_CALL_TRANSACTION + 3,
       SYNC = ::android::IBinder::FIRST_CALL_TRANSACTION + 4,

This number is then used by the calling side to map called method to flat Parcel buffer and by receiving side of IPC to select the generated method to unmarshall the serialized parameters data and finally call the real implementation.

Thus if you replace the method number 1 definition on the calling side, but still have old implementation on the receiving side, you will call the old implementation with completely bogus data. There is no type information in the serialized Parcel data of method arguments (besides the method number itself), so it will happily deserialize new method call parameters buffer as old ones and try to call implementation.

smokku
  • 1,256
  • 13
  • 22