我看到了一些SO帖子,其中讨论了如何以编程方式结束电话,例如this one。是的,人们专注于结果,但没人能真正解释为何起作用的原因吗?

我尝试了代码,效果很好。但是我想知道更多有关下面发生的事情的细节吗?为什么通过创建 ITelephony.aidl ,在我们的项目中公开了android隐藏的内部ITelephony接口(interface)?我们自己如何创建 ITelephony.aidl 和自动生成的Java(/gen/ITelephony.java)链接到 android的ITelephony接口(interface)?仅仅是因为名称匹配(软件包名称和辅助文件名称)吗?

TelephonyManager tm = (TelephonyManager) context
                .getSystemService(Context.TELEPHONY_SERVICE);

Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);

//Why does the android internal ITelephony interface is exposed after created the ITelephony.aidl?
com.android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(tm);
telephonyService.endCall();

最佳答案

实际上,没有必要将ITelephony.aidl添加到您的项目中,这只是一种方便。您也可以这样做:

TelephonyManager tm = (TelephonyManager) context
            .getSystemService(Context.TELEPHONY_SERVICE);
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
Object telephonyService = m.invoke(tm); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke endCall()

在幕后,所有这些工作都使用Java反射来访问私有(private)(即,未公开记录)的方法。通过阅读开源(即公开可用)的Android源代码,您可以弄清楚那里有什么方法,以及它们做了​​什么。一旦知道了那里有什么,它做什么了,就可以使用反射来到达它,即使它是“隐藏的”。
TelephonyManager类是使用远程服务实现的。如果要请求TelephonyManager为您做某事,请在TelephonyManager上调用一个方法(这是公开记录的部分),并在内部调用远程电话服务以实际完成工作。这是使用AIDL(这是一种“远程过程调用”)完成的。远程服务可以执行未通过TelephonyManager类公开公开的事情。您在这里所做的是使用getITelephony()获取“远程过程调用”接口(interface)的客户端。这将返回ITelephony类型的对象。此类具有一个名为endCall()的方法。一旦有了ITelephony类型的对象,我们就可以获取其Class对象,然后从Class中获取endCall()方法。一旦有了方法,就可以访问它,然后调用它。方法endCall()在远程过程调用的客户端中。现在,该方法将消息发送到电话管理器服务(在远程服务器上运行),并要求其结束调用。

由于ITelephony.aidl的源代码是公开可用的,因此您可以将源代码放入项目中,并且IDE将从ITelephony.java生成ITelephony.aidl(包含远程过程调用的客户端)。然后,您只需import即可,您的IDE现在将知道ITelephony类及其方法。这允许编译器在编译项目时生成正确的字节码。在Android设备上运行此代码时,请调用Android框架以获取ITelephony对象,然后将其强制转换为com.android.internal.telephony.ITelephony。从那时起,只要您拥有ITelephony.java的Java代码与返回的ITelephony对象的实际类定义相匹配,就可以使用生成的ITelephony访问对象的方法和字段。如果类定义不匹配,则VM将引发适当的异常。

我希望这回答了你的问题。我不确定您已经知道多少,所以也许我提到了您已经知道的东西。如果是这样,对此感到抱歉。如果不清楚,请指出您完全不了解的内容。

关于android - 为什么ITelephony.aidl可以工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18977012/

10-13 03:06