まったりAndroid Framework Code Reading #3 に参加してきた
まったり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をもっと調べてみよう。