android - ¿Por qué funciona ITelephony.aidl?
performance android-intent (1)
Vi algunas publicaciones de SO que trataban sobre cómo terminar una llamada telefónica programmtically, por ejemplo, esta . Sí, la gente se enfoca en el resultado, pero nadie realmente explica la razón por la que funciona.
Probé el código, funciona bien. Pero me gustaría saber más detalles sobre lo que está sucediendo debajo? ¿Por qué al crear el ITelephony.aidl , la interfaz interna de ITelephony
está expuesta en nuestro proyecto? ¿Cómo crea él mismo ITelephony.aidl y el enlace java generado automáticamente (/gen/ITelephony.java) a la interfaz ITelephony
de ITelephony
? ¿Es solo por la coincidencia de nombres (nombre del paquete y nombre del archivo 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();
En realidad, agregar ITelephony.aidl
a su proyecto no es necesario, es solo una conveniencia. Podrías hacerlo de esta manera:
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()
Bajo las cubiertas, todo esto funciona usando la reflexión de Java para acceder a métodos privados (es decir, no documentados públicamente). Puede averiguar qué métodos hay y qué hacen al leer el código fuente de código abierto de Android (es decir, disponible públicamente). Una vez que sepa qué hay allí y qué hace, puede usar el reflejo para llegar a él, aunque esté "oculto".
La clase TelephonyManager
se implementa utilizando un servicio remoto. Si desea solicitar al TelephonyManager
que haga algo por usted, llame a un método en TelephonyManager
(esa es la parte documentada públicamente) e internamente hace una llamada al servicio de telefonía remota para que realmente haga el trabajo. Esto se hace usando AIDL, que es una especie de "llamada de procedimiento remoto". El servicio remoto puede hacer cosas que no están expuestas públicamente a través de la clase TelephonyManager
. Lo que está haciendo aquí es obtener el lado del cliente de la interfaz de "llamada a procedimiento remoto" usando getITelephony()
. Esto devuelve un objeto de tipo ITelephony
. Esta clase tiene un método llamado endCall()
. Una vez que tenemos el objeto de tipo ITelephony
, podemos obtener su objeto Class y luego obtener el método endCall()
de la clase. Una vez que tenemos el método, lo hacemos accesible y luego lo llamamos. El método endCall()
está en el lado del cliente de la llamada a procedimiento remoto. El método ahora envía un mensaje al servicio del administrador de telefonía (que se está ejecutando en un servidor remoto) y le pide que finalice la llamada.
Dado que el código fuente para ITelephony.aidl
está disponible públicamente, puede colocar el código fuente en su proyecto y su IDE generará ITelephony.java
(que contiene el lado del cliente de la llamada a procedimiento remoto) desde ITelephony.aidl
. A continuación, puede import
eso y su IDE ahora sabrá sobre la clase ITelephony
y sus métodos. Esto permite que el compilador genere el código de byte correcto al compilar su proyecto. Cuando ejecuta este código en un dispositivo Android, llama al marco de Android para obtener el objeto ITelephony
y luego lo ITelephony
en com.android.internal.telephony.ITelephony
. A partir de ese momento, puede acceder a los métodos y campos del objeto utilizando ITelephony.java
generado, siempre que el código Java que tiene para ITelephony
coincida con la definición de clase real del objeto ITelephony
devuelto. Si las definiciones de clase no coinciden, la VM arrojará una excepción apropiada.
Espero que esto responda tu pregunta. No estaba exactamente seguro de cuánto sabías sobre esto, así que tal vez mencioné cosas que ya sabes. Si es así, perdón por eso. Si esto no está claro, indique qué es exactamente lo que no entiende.