32

我看到一些 SO 帖子讨论了如何以编程方式结束电话,例如这个。是的,人们关注结果,但没有人真正解释它起作用的原因?

我尝试了代码,它运行良好。但我想知道更多关于下面发生了什么的细节?为什么通过创建ITelephony.aidl,在我们的项目中暴露了 android 隐藏的内部ITelephony接口?我们自己如何创建ITelephony.aidl和自动生成的 java (/gen/ITelephony.java)链接到android 的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);

//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(); 
4

2 回答 2

83

实际上,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 反射来访问私有(即:未公开记录的)方法。通过阅读开源(即:公开可用的)Android 源代码,您可以了解有哪些方法以及它们的作用。一旦你知道那里有什么以及它做了什么,你就可以使用反射来获得它,即使它是“隐藏的”。

该类TelephonyManager是使用远程服务实现的。如果您想请求TelephonyManager为您做某事,您可以在TelephonyManager(这是公开记录的部分)上调用一个方法,并在内部调用远程电话服务以实际完成工作。这是使用 AIDL 完成的,它是一种“远程过程调用”。TelephonyManager远程服务可以做一些不通过类公开的事情。您在这里所做的是使用getITelephony(). 这将返回一个 类型的对象ITelephony。这个类有一个名为 的方法endCall()。一旦我们有了 type 的对象ITelephony,我们就可以得到它的 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 将抛出适当的异常。

我希望这回答了你的问题。我不确定你已经知道多少,所以也许我提到了你已经知道的东西。如果是这样,很抱歉。如果不清楚,请指出您到底不明白什么。

于 2013-09-24T18:21:04.297 回答
0

实际上,不需要将 ITelephony.aidl 添加到您的项目中,这只是为了方便。你也可以这样做: 正确答案

于 2018-09-24T06:58:13.427 回答