ミッションたぶんPossible

どこにでもいるシステムエンジニアのなんでもない日記です。たぶん。

タブレット型のAndroidは携帯端末固有IDが取れない!?

 本来先月末までだったはずのPush通知を使ったAndroidプロトタイプアプリ開発は、一昨日ようやく検収を完了することができました。C2DMは相変わらず意味不明な存在ですが、さっさとGoogle Labsから卒業してくれるのを待つほかないのかもしれません。


 まぁ今回は別の話題。上記のアプリはAndroid OS 2.2(SHARP IS03)が対象なんですが、試しにモトローラ社のXOOMというタブレット端末(OS 3.0)で動かしてみようとしたら端末固有IDが取得できないんですわ。よくよく調べてみたら今回のプロトタイプでは以下のように取得してたんですけど、これじゃ電話番号と紐付いてない筐体の端末固有IDは取れないようになってるみたいです。

// 端末管理クラスの起動
TelephonyManager mng = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
// Phone Number
String phoneNumber = mng.getLine1Number();
// SIM国別コード
String simCountryIso = mng.getSimCountryIso();
// SIMシリアルナンバー
String simSerialNumber = mng.getSimSerialNumber();
// 携帯端末固有ID
String deviceId = mng.getDeviceId();


 XOOMはタブレットだから電話じゃない、当然電話番号なんか割り振られてない、だから端末固有IDも取れない。う〜ん深いですねぇ、実にめんどくさい。
 ※5/13追記:正確には「電話番号が割り振られてないから」ではなく、「SIMカードが刺さってないから」ですね。案の定SIMカードのシリアル番号も取得できませんでした。


 とはいえ次のターゲットはこのXOOMなので同じアプリが動かせなきゃいけない。なのでTelephonyManager以外から携帯端末固有IDの代替になるユニークな情報が何か取得出来ないか調べています。今のところお客様の担当の方から「FCC ID」と「機械製造番号」が使えるんじゃないか、という情報を頂戴しましたんで、ちょっと調べた内容を備忘録的に書いておきます。

FCC

通信、電信及び電波を管理する米国の連邦政府機関で、Federal Communications Commission(FCC連邦通信委員会)と呼ばれています。ラジオ、テレビ、衛星通信、無線通信など、米国内の各州間の通信や国際通信を規制する役目を果たしています。一般の電気製品に対する規制については、47CFRというものがあり、そのなかでもPart15「無線周波数機器」Part18「ISM機器」及びPart68「電話回線への端末機器接続」などが電気製品の規制として有名です。意図的に電波を放射する機器(例:無線LAN機器)は、FCCの認証を取得しなければ米国内での販売は認められていません。FCCの認証を取得している機器に対しては、FCC IDが付与され、製品上に表示されることになっています。

   — 輸出・海外規格|FACTORIST|キーエンス

MotorolaAndroid携帯端末、MorrisonがアメリカのFCC(アメリカの連邦通信委員会)を通過しました。

(中略)

FCC id:IHT56KV1によると、モデルナンバーは、CLIQ MB200

   — Motorola Morrison FCC通過 (Androidデバイス) |

 …このFCC IDって、もしかして端末固有の情報じゃなくて、製品単位の情報なんじゃないのか?それじゃ意味無いじゃん!


 一方の「機械製造番号」についてはその名の通り、携帯端末の製造番号。間違いなくユニークなIDです。こちらはXOOMの箱に書いてあるらしいので、最悪そこから情報を取ってもいいのですが、できればJavaで取得したい。色々調べていたら「シリアル番号」と「AINDROID_ID」というものが取れる様子。「機械製造番号」と同じものを指すかどうかは分かりませんが、さしあたって確認してみる必要はありそうです。


 ちなみに「シリアル番号」は以下の様な方法で取れるようです。Javaからの取得じゃないけど、なんか取っ掛かりになるかも。

エミュレーター/デバイス(実機)のシリアル番号を取得するには、
adb get-serialno
を実行します。
実行結果は、エミュレーターの場合、
emulator-5554
などとなります。

   — [Android] シリアル番号(Serial no)取得 - adakoda

 ANDROID_ID」は以下の様な感じらしいです。※5/13修正:すみません、間違ってました。以下はANDROID_IDを取り出す為の単なる定数、keyです。

String id = android.provider.Settings.Secure.ANDROID_ID;

   — SE奮闘記: 【Android開発】端末の固有IDを取得する

 ※5/13追記:正しいANDROID_IDの取り出し方は以下。

import android.provider.Settings;

public class App extends Activity {

    public App() {
        String deviceId
          = Settings.Secure.getString(this.getContentResolver(), Settings.System.ANDROID_ID);
    }

}

   — Androidで個体識別番号を取得する - terurouメモ

 今は機械製造番号とSIMカードのIDを組み合わせて端末情報を管理できないかなぁと色々調べてます。明日実機で確認するので、なんか分かったら追記します。




5/13追記

 結論から言うと機械製造番号とシリアル番号、そしてANDROID_IDは全て別のものでした。


 機械製造番号は前述の通り、タブレット端末の製品の箱に記載されています。これをJavaから取り出す方法は現時点では見つかっていません。


 続いてシリアル番号、これはSIMのシリアル番号ではなくてタブレット端末そのもののシリアル番号ですが、adbコマンドで確認できるほか、EclipseのDevicesビューからでも確認できます。



 このシリアル番号を取得するには以下の様に実装します。ちなみに「android.os.Build.SERIAL」が使えるのはOS 2.3から。2.2以前はコンパイルエラーになります。

String serialId = android.os.Build.SERIAL;

 これをLogCatに出力すると確かにDevicesビューで表示されるシリアル番号と一致した値が取得できることを証明できました。ただ、OS 2.3からしか使えないことを考えると使い勝手は微妙ですね。いちいちOSバージョンごとに提供するパッケージ変えなくちゃいけないとか、ナンセンスすぎる。


 次にANROID_ID、前述の方法で取り出す事が可能です。(※取得方法を間違って記載していた為修正しました。ご注意下さい。)出力はToastでもLogCatでも好きな方法でやって下さい。ちなみに、Android OS 3.0からLog.d()メソッドの第二引数がnullの場合、NullPointerExceptionが発生するようになっていますので注意して下さい。(オレが試した限りではOS2.2までは単にログが出力されないだけでした)。

 ところが、よくよく調べてみるととんでもないことが発覚!

ANDROID_ID、より正確に言うとSettings.Secure.ANDROID_IDは、64bit幅で、端末が最初に起動したときに生成され、端末に保存される。端末が初期化されるとリセットされる。

   — Android Zaurusの日記


 今回はデバイス管理APIを使って端末を工場出荷時状態に戻す(つまり端末を初期化する)という要件があるんです。


 初期化の度に値が変わっちゃったら使えないじゃん!


 …ちなみに以下のページを参考にシリアル番号同様に一意な値が無いか確認しましたが、残念ながら芳しい結果は得られませんでした。


Build | Android Developers


…残念ながら、どうやら現状まともに使えそうなユニークIDはこのANDROID_IDくらいしかなさそうです。

今回の結論

  • SIMカードの無い端末は、Android OS 2.2以前が駆逐されるまではANDROID_IDでごまかし後は運用でカバー、OS 2.2以前が駆逐されたらシリアル番号を使おう!

…めんどくせーな、なんで最初っからシリアル番号をJavaから取れるようにしといてくれなかったのかね?