【问题标题】:Why ITelephony.aidl works?为什么 ITelephony.aidl 有效?
【发布时间】:2013-09-29 09:32:49
【问题描述】:

我看到一些 SO 帖子讨论了如何以编程方式结束电话,例如,this one。是的,人们只关注结果,但没有人真正解释为什么会起作用?

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

【问题讨论】:

    标签: android performance android-intent aidl telephonymanager


    【解决方案1】:

    实际上,在您的项目中添加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() 的方法。一旦我们有了ITelephony 类型的对象,我们就可以获取它的Class 对象,然后从Class 中获取方法endCall()。一旦我们有了方法,我们就可以访问它,然后调用它。方法endCall() 位于远程过程调用的客户端。该方法现在向电话管理器服务(在远程服务器中运行)发送一条消息,并要求它结束通话。

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

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

    【讨论】:

    • 只有我还是这不适用于 Android 4.2.2
    • 很棒,详细的答案。谢谢。注意:我不相信在 Android 4.0.3 之后阻止调用有效,因为这个 API 被删除了。
    【解决方案2】:

    实际上,将 ITelephony.aidl 添加到您的项目中并不是必须的,它只是为了方便。你也可以这样做: correct answer

    【讨论】:

    • 链接将来可能会更改或删除。请在您的答案中包含该链接中的要点。
    猜你喜欢
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    • 2018-01-04
    • 2021-05-09
    • 2011-11-10
    相关资源
    最近更新 更多