まったりAndroid Framework Code Reading というイベントに参加してきました。Androidのソースコードをまったり読みましょう、という会です。仕事でNFCらへんのAPIを使ったのですが、裏側どうなってるのかなぁと思ってたので参加してみることにしました。
このイベントおかげでまったり読むことができて有意義な時間を過ごすことができました。そして、メルカリさんの会場は綺麗でビールも普段は出てこないようなおいしそうなものばかりでした(私は酒止めたのですが・・・)。
コードリーディング楽しかったのでこれからも参加したいなー。
コード読む
NFC絡みのコードを読む!
ブラウザだけでAndroidのコード読めました。便利。OpenGrokというものが使われているみたい。
https://sites.google.com/site/devcollaboration/codesearch
Full search で nfc と入力して検索。 /frameworks/base/core/java/android/nfc/ を開く。
android.nfc.NfcAdapter を読み始めます。適当に流しよみしてると getNfcAdapter というstaticメソッドが。このメソッドで NfcAdapter をインスタンス化してる。 getNfcAdapter を定義してる箇所をクリックすると getNfcAdapter で検索してくれた。OpenGrok便利。
getNfcAdapter を呼んでいるのは android.nfc.NfcManager 。 NfcManager は NfcAdapter を保持してるだけ。 NfcManager のコンストラクタを呼び出している箇所を探す。
android.app.SystemServiceRegistry のstatic初期化子で、 NfcManager のインスタンスを取得してます。
260 registerService(Context.NFC_SERVICE, NfcManager.class,
261 new CachedServiceFetcher<NfcManager>() {
262 @Override
263 public NfcManager createService(ContextImpl ctx) {
264 return new NfcManager(ctx);
265 }});
主催者の方に聞いたところ、 SystemServiceRegistry はAndroid端末の起動時に各種システムサービスを登録してるらしい。
さて、ここまでで、Android端末起動時にシステムサービスが登録され NfcAdapter のインスタンスが作られる、とこまでわかった。
次は、FeliCaカードを端末にタッチした時にIntentが発行されるところを読みたい。
いろいろ眺めてると、 com.android.nfc.NfcDispatcher に怪しいところが。
193 boolean tryStartActivity() {
194 // Ideally we'd have used startActivityForResult() to determine whether the
195 // NfcRootActivity was able to launch the intent, but startActivityForResult()
196 // is not available on Context. Instead, we query the PackageManager beforehand
197 // to determine if there is an Activity to handle this intent, and base the
198 // result of off that.
199 List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(intent, 0,
200 ActivityManager.getCurrentUser());
201 if (activities.size() > 0) {
202 context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
203 return true;
204 }
205 return false;
206 }
tryStartActivity を呼び出しているのは、多分 NfcDispatcher の dispatchTag メソッドかな・・・。
220 /** Returns:
221 * <ul>
222 * <li /> DISPATCH_SUCCESS if dispatched to an activity,
223 * <li /> DISPATCH_FAIL if no activities were found to dispatch to,
224 * <li /> DISPATCH_UNLOCK if the tag was used to unlock the device
225 * </ul>
226 */
227 public int dispatchTag(Tag tag) {
この dispatchTag メソッドを呼んでるのは、これかなー・・・。 com.android.nfc.NfcService
921 @Override
922 public void dispatch(Tag tag) throws RemoteException {
923 NfcPermissions.enforceAdminPermissions(mContext);
924 mNfcDispatcher.dispatchTag(tag);
925 }
もしくは、内部で定義されている NfcServiceHandler 。
だんだん分からなくなってきたけど、この NfcService を呼び出してるのはどこか、というところ全然分からなくなってきた。
NfcService のコードを読んでると、以下のような記述がある。
final class NfcAdapterService extends INfcAdapter.Stub {
INfcAdapter というは、 /frameworks/base/core/java/android/nfc にある、 INfcAdapter.aidl で定義されているインタフェース。実は最初からこの .aidl というのが気になっててちょっとだけ調べてた。
どうやら、プロセス間通信を行うコードを自動生成するための仕組みがAndroidにはあって、それをAIDLと言うみたい。
NfcAdapter の中の以下のコードが怪しいなぁというところで時間切れ。
471 /** get handle to NFC service interface */
472 private static INfcAdapter getServiceInterface() {
473 /* get a handle to NFC service */
474 IBinder b = ServiceManager.getService("nfc");
475 if (b == null) {
476 return null;
477 }
478 return INfcAdapter.Stub.asInterface(b);
479 }
AIDLをもっと調べてみよう。