Подтвердить что ты не робот

Почему работает ITelephony.aidl?

Я увидел несколько сообщений SO, в которых обсуждалось, как программировать телефонный вызов, например этот. Да, люди сосредотачиваются на результате, но никто не объясняет причины почему он работает?

Я пробовал код, он работает хорошо. Но я хотел бы узнать подробности о том, что происходит внизу? Почему при создании ITelephony.aidl в нашем проекте отображается скрытый внутренний интерфейс ITelephony. Каким образом мы создали ITelephony.aidl и автоматически сгенерированную ссылку java (/gen/ITelephony.java) на android ITelephony интерфейс? Это связано только с совпадением имени (имя пакета и имя файла helpl)?

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

Ответ 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-рефлексии для доступа к закрытым (т.е. не публично документированным) методам. Вы можете выяснить, какие методы существуют, и что они делают, читая исходный код с открытым исходным кодом (то есть: общедоступный). Когда вы узнаете, что там и что он делает, вы можете использовать отражение, чтобы добраться до него, даже если оно "скрыто".

Класс TelephonyManager реализуется с использованием удаленного сервиса. Если вы хотите запросить TelephonyManager что-то сделать для вас, вы вызываете метод на TelephonyManager (который публично задокументированная часть) и внутренне он делает вызов службе удаленной телефонной связи, чтобы фактически выполнить эту работу. Это делается с помощью AIDL, который является своего рода "удаленным вызовом процедуры". Удаленная служба может выполнять действия, которые не публиковались публично через класс TelephonyManager. Что вы здесь делаете, это получить клиентский интерфейс "удаленного вызова процедур", используя getITelephony(). Это возвращает объект типа ITelephony. Этот класс имеет метод с именем endCall(). Когда у нас есть объект типа ITelephony, мы можем получить его объект класса, а затем получить метод 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 выдаст соответствующее исключение.

Надеюсь, это ответит на ваш вопрос. Я не был точно уверен, как много вы уже знали об этом, так что, возможно, я упомянул то, что вы уже знаете. Если так, извините. Если это не ясно, укажите, что именно вы не понимаете.