我有两个应用程序:一个名为 my-app.apk ,另一个名为 my-service.apk 。服务应用程序只定义了一个Android Service,它可以被主应用程序绑定以执行某些方法。这是使用Androids AIDL界面完成的,并且效果很好 - 到目前为止。
现在我想改变服务的界面,我想知道我需要注意什么。我将 my-service.apk 的文件IRemote.aidl更改为以下内容:
package com.example.myservice;
interface IRemote {
void printHello();
void print(int i);
}
出于好奇,我将 my-app.apk 的IRemote.aidl更改为以下内容(注意差异!):
package com.example.myservice;
interface IRemote {
void printHello();
void printYeahThisHasADifferentNameAndParam(String s);
}
现在我得到了一个完全出乎意料的结果:对
的调用printYeahThisHasADifferentNameAndParam("hello world");
从我的应用程序导致日志输出“11”。为什么?
所以这是我的问题:
提前感谢您的帮助! : - )
干杯, 马克
答案 0 :(得分:2)
如果您查看AIDL编译器生成的代码,您将看到RPC通过Binder按顺序号调用方法。接口中的每个方法都会分配编号,例如:
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,
然后,调用方使用此数字将被调用的方法映射到平面包裹缓冲区,并通过接收IPC的一侧来选择生成的方法来解组序列化的参数数据,最后调用实际的实现。
因此,如果您在调用端替换方法编号1
定义,但在接收端仍然具有旧实现,则将使用完全伪造的数据调用旧实现。方法参数的序列化Parcel数据中没有类型信息(除了方法编号本身),因此它很乐意将新方法调用参数缓冲区反序列化为旧的,并尝试调用实现。