TL;DR
以下のように、 iphonesubinfo
サービスに 4
を渡すのがAndroid 8以降は正しい。
adb shell service call iphonesubinfo 4
よくある以下のやり方は、 API Level 30(Android 11相当)以降で deprecated指定されるので注意が必要
adb shell service call iphonesubinfo 1
以下、ちょっとだけ詳しい解説をします。
そもそも一体何をしているのか
もう一度コードを貼ります。
adb shell service call iphonesubinfo 4
このうち adb shell
についてはadbのshellにコマンドを引き渡すための記述に過ぎないので、実際にAndroidの中で実行されているのは service call iphonesubinfo 4
となります。
service
とはなにか
service
はAndroid上で動作しているサービスの操作を行うものです。Linuxにも同盟のコマンドはありますが、それとは似て非なるものと言えます。
-h
で表示される文言は以下のようなものです。
Usage: service [-h|-?]
service list
service check SERVICE
service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null | fd f | nfd n | afd f ] ...
Options:
i32: Write the 32-bit integer N into the send parcel.
i64: Write the 64-bit integer N into the send parcel.
f: Write the 32-bit single-precision number N into the send parcel.
d: Write the 64-bit double-precision number N into the send parcel.
s16: Write the UTF-16 string STR into the send parcel.
null: Write a null binder into the send parcel.
fd: Write a file descriptor for the file f to the send parcel.
nfd: Write file descriptor n to the send parcel.
afd: Write an ashmem file descriptor for a region containing the data from file f to the send parcel.
上記を見ると、service call iphonesubinfo 4
の意味が見えてきます。
call
はサービスの呼び出しを行い、iphonesubinfo
はサービス名、 4
はコードというわけですね。
Android上で動作するサービス
Android上で動作するサービスの取得方法も先程のヘルプを見ればなんとなくわかりますね。そう、 service list
です。やってみましょう。
Found 199 services:
0 DockObserver: []
1 SurfaceFlinger: [android.ui.ISurfaceComposer]
2 accessibility: [android.view.accessibility.IAccessibilityManager]
3 account: [android.accounts.IAccountManager]
4 activity: [android.app.IActivityManager]
5 activity_task: [android.app.IActivityTaskManager]
6 adb: [android.debug.IAdbManager]
7 alarm: [android.app.IAlarmManager]
8 android.hardware.identity.IIdentityCredentialStore/default: []
9 android.hardware.power.IPower/default: []
10 android.hardware.rebootescrow.IRebootEscrow/default: []
(以下省略)
ここで注目すべきは、多くのサービスがサービス名と合わせて、 android.view.accessibility.IAccessibilityManager
のようなインタフェース名を公開していることです。実はこれらのファイルの多くはAndroidのソースコードに含まれており、例えば IAccesibilityManager
は以下になります。
拡張子 *.aidl
はAndroidのインタフェース定義言語(AIDL)を表し、名前通りそのAndroidサービスとやり取りする際のインターフェースが記述されています(記述はすごくJavaっぽいです)
Androidサービスの呼び出し方
同様に iphonesubinfo
を探すと、以下のコードが見つかります。
中身は以下のような感じです。
interface IPhoneSubInfo {
/** @deprecated Use {@link #getDeviceIdWithFeature(String, String) instead */
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
String getDeviceId(String callingPackage);
/**
* Retrieves the unique device ID, e.g., IMEI for GSM phones.
*/
String getDeviceIdWithFeature(String callingPackage, String callingFeatureId);
/**
* Retrieves the unique Network Access ID
*/
String getNaiForSubscriber(int subId, String callingPackage, String callingFeatureId);
/**
* Retrieves the unique device ID of a phone for the device, e.g., IMEI
* for GSM phones.
*/
String getDeviceIdForPhone(int phoneId, String callingPackage, String callingFeatureId);
/**
* Retrieves the IMEI.
*/
String getImeiForSubscriber(int subId, String callingPackage, String callingFeatureId);
/**
* Retrieves the software version number for the device, e.g., IMEI/SV
* for GSM phones.
*/
String getDeviceSvn(String callingPackage, String callingFeatureId);
//(中略)
}
ではこのAIDLのメソッドを呼び出すに当たり、最後の 4
という数字は何を意味するのか。
実はこの数字は、AIDLに定義されているメソッドの順番(1スタート)になっています。
したがって、 service call iphonesubinfo 4
で呼び出されるメソッドは、 getImeiForSubscriber
となります。そう、これがIMEIを取得するメソッドだったのです。
では service call iphonesubinfo 1
で呼び出されるメソッドは、当然戦闘のメソッドですが、それは以下のようなアノテーションが付されています。
/** @deprecated Use {@link #getDeviceIdWithFeature(String, String) instead */
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
String getDeviceId(String callingPackage);
そう、30以降ではサポートされず、別のメソッドを使うように、と書いてあります。
ただ、そもそもその「別のメソッド」というのが getImeiForSubscriber
じゃないじゃないか、という話もあると思います。使うべきとされているのはこちらのメソッドです。
/**
* Retrieves the unique device ID, e.g., IMEI for GSM phones.
*/
String getDeviceIdWithFeature(String callingPackage, String callingFeatureId);
はい、記述どおり、このメソッドはIMEIを返すことを保証しないのです。それは実は内部の実装依存です。したがってIMEIと明確に指定して抜き出したい場合には、 getImeiForSubscriber
を、すなわち service call iphonesubinfo 4
をコールするのが望ましい、という話になります。
おつかれさまでした。