web-dev-qa-db-ja.com

ITelephony.aidlが機能する理由

私はいくつかのSOプログラムで電話を終了する方法について議論した投稿を見ました、例えば これ 。うん、人々は結果に焦点を合わせますが、実際には誰も説明しません理由なぜそれが機能するのですか?

私はコードを試しました、それはうまくいきます。しかし、私はその下で何が起こっているのかについてもっと詳しく知りたいですか? ITelephony.aidlを作成することにより、Android非表示の内部ITelephonyインターフェイスがプロジェクト?私たち自身はどのように作成しましたかITelephony.aidl&自動生成されたJava(/gen/ITelephony.Java)link toAndroidのITelephonyインターフェイス?名前が一致しているためか(パッケージ名とエイドルファイル名)?

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(); 
28
Mellon

実際には、プロジェクトに_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.Java_(リモートのクライアント側を含む)を生成します。プロシージャコール)_ITelephony.aidl_から。そうすれば、それをimportするだけで、IDEはITelephonyクラスとそのメソッドについて知ることができます。これにより、コンパイラはプロジェクトのコンパイル時に正しいバイトコードを生成できます。このコードをAndroidデバイスで実行する場合は、Androidフレームワークを呼び出してITelephonyオブジェクトを取得し、それを_com.Android.internal.telephony.ITelephony_にキャストします。それ以降、ITelephonyのJavaコードが、返されたITelephonyオブジェクトの実際のクラス定義と一致する限り、生成された_ITelephony.Java_を使用してオブジェクトのメソッドとフィールドにアクセスできます。クラス定義が一致しない場合、VMは適切な例外をスローします。

これがあなたの質問に答えてくれることを願っています。あなたがこれについてどれだけ知っているか正確にはわからなかったので、あなたがすでに知っていることについて言及したかもしれません。もしそうなら、それについて申し訳ありません。これが明確でない場合は、理解できないことを正確に示してください。

80
David Wasser

実際、ITelephony.aidlをプロジェクトに追加する必要はありません。それは単に便利なことです。次のようにすることもできます: 正解

0
venkatkural