たくさんの自由帳
Androidのお話
たくさんの自由帳
投稿日 : | 0 日前
文字数(だいたい) : 3515
この辺の技術はほとんどがクローズドソースというか、仕様が公開されていないので、
結局何が出来るのかよく分からずあんまりおもしろくなかった。
root 権限が必要です。自己責任で。
APKを作りました、が、AT コマンドを知っていないと何も出来ないです。AT コマンド詳しい人がいれば(実在するの?)このアプリでいろいろ叩いてみて遊べるかもしれません。
起動直後はデバイスが/dev/smd0とかになってますが、ATコマンドの欄でコマンドを実行して応答がなければ/dev/smd7とかに変更してみてください。
テスト用コマンドはATです。OKが返ってくるはず。
Qualcommしか知りません。(Google PixelとかはExynosなので!)
最難関ですね。修理出来ないので壊したら終わり
ところで、電波測定を最大限楽しむにはSIM フリーじゃなくてキャリアで売られているスマホを買う必要が多分あります。
理由としては、
5G SAに接続できるか怪しい転用5G(なんちゃって5G / NR 化)を掴むためにはドコモで買った端末が必要(IMEIをチェックしているらしい)
au / softbankは普通にキャリア以外の端末で転用5Gつながるしかし、キャリアで買ったスマホはroot化が(ほぼ)出来ない状態です。壊れるかもしれない(一向に起動アニメーションが終わらない等)ので塞がれて正解ですが。。。
Android 4.xくらいの時までは盛り上がっていたはずで、(Nexus 7いじるの楽しかったなあ)Superuser、SuperSU、あとはKingRootとかいう怪しい雰囲気のやつとかありましたね、懐かしい
Xperia Z3くらいでroot化の文化が途絶えてしまったわけですが、Samsungとかは今でもできるらしい?おサイフケータイだかNFCが4ぬらしいけど。Google Pixelはどうかなあ、昔はSIMロック解除さえすればBootloaderがアンロック出来たはず?
国内版Pixel 3 XLにAndroid 12 DPを入れる - たくさんの自由帳
https://takusan.negitoro.dev/posts/android_12_dp_hitobashira/
なので、電波測定を犠牲にしてrootが必要ならSIMフリーを買うしかない。SIMフリーとして売られてる端末を買えばroot行けるはず。
Xperia もSIMフリー買えば今でもできるらしい?高い金払って壊れる可能性があるものに価値を見いだせるかというと、、、
Android Studio入れたら付いてくるっしょ
多分adb単品も行けるはず?platform-toolsだけ入れる方法があった気がする
先述の通りAndroid端末をroot化、もといsuコマンドが叩ける状態にする必要があります。
コマンドプロンプトでもGitBashでもなんでも良いのでターミナルさんを開いてください。adb shellした後suすると、rootユーザーに昇格できます。$(ドルマーク)だったのが#(シャープ、いげた)に変化するはず。
C:\Users\takusan23>adb shell
OnePlus7TPro:/ $ su
OnePlus7TPro:/ #あ、Magiskに許可するか聞かれたら許可してあげてください。
にはもう一個手間が必要で、AT コマンドを叩く先を探す必要があります。
というのも、端末によっては/dev/smd0だったり、/dev/smd7だったりと違うみたいなんですよね。
とりあえずこれを叩いてみます。最後の\rが必要です。
成功すればOKという文字が出ます。
echo -e "AT\r" > /dev/smd7 && cat /dev/smd7どうでしょうか。ATの後にOKがでましたか?出ていればAT コマンドを叩ける状態です。AT\rの部分を好きなAT コマンドにすれば良いのですが、クローズドソースというか仕様が公開されていないため、何を叩けば良いのかは調べるしかないです。
AT
OKちなみにCtrl+Cで抜けることが出来ます(操作ができるようになります)
/dev/smd7の部分を/dev/smd0とかにすれば良いのですが、まずsmdが何種類あるのか見てみましょう。
見つかったもの全てにAT\rを投げてOKが返ってくるものがあればそれを使えば良いはずです。
以下のコマンドを叩きます
ls /dev/smd*すると、こんな感じにsmd7とかが一覧で表示されるはず。(以下省略)
/dev/smd0 /dev/smd7あとは出てきたsmdに対してAT\rを投げていってOKが出てくるまで繰り返せばおけ。
(/dev/smd0の部分を置き換えていく)
echo -e "AT\r" > /dev/smd0 && cat /dev/smd0ATIを叩くと端末の情報が取れるそうです。
echo -e "ATI\r" > /dev/smd7 && cat /dev/smd7適当に置き換えてますがこんな感じ
OnePlus7TPro:/ # echo -e "ATI\r" > /dev/smd7 && cat /dev/smd7
ATI
Manufacturer: QUALCOMM INCORPORATED
Model: 0000
Revision: xxxxx
SVN: 00
IMEI: 00000
+GCAP: +CGSM
OKAT+CLACを叩くと表示できるそうです。
端末によっては塞がれている場合があるそうです。
OnePlus7TPro:/ # echo -e "AT+CLAC\r" > /dev/smd7 && cat /dev/smd7
AT+CLAC
&C
&D
&E
&F
&S
&V
&W
以下省略...AT$QRSRPを叩くと、EARFCN(バンド)が取れるらしい、、、ですがうまく行きませんでした。OKが帰ってきますが何もでてきません。
OnePlus7TPro:/ # echo -e "AT$QRSRP\r" > /dev/smd7 && cat /dev/smd7
AT
OKAT+COPS=?を叩くと、しばらく待った後に近くの基地局を返してくれるそうです。
先述の通りOKが表示されるまで、少し時間がかかります。
全部見せて良いのか知らんから隠すわ。
OnePlus7TPro:/ # echo -e "AT+COPS=?\r" > /dev/smd7 && cat /dev/smd7
AT+COPS=?
+COPS: (3,"JP DOCOMO","DOCOMO","44010",2) 以下省略
OKAT+COPS?で接続中のが見れるらしい。確かにLINEMOなのであっていそう
OnePlus7TPro:/ # echo -e "AT+COPS?\r" > /dev/smd7 && cat /dev/smd7
AT+COPS?
+COPS: 0,0,"SoftBank LINEMO",7
OKpingコマンドとかはRuntime.getRuntime().exec()で良いのですが、root権限が(suする)必要な場合。su -cした後にコマンドを入れればいいらしいです。
su -c この後にコマンド最小限の実装例です。
文字列で渡すのではなく、arrayOfで一つ一つ分解するのが良いらしいです。
lifecycleScope.launch(Dispatchers.IO) {
val command = arrayOf("su", "-c", "whoami")
val process = Runtime.getRuntime().exec(command)
process.inputStream.bufferedReader().forEachLine { readLine ->
// 出力を logcat に
println(readLine)
}
}Magiskで許可するか聞かれるので許可してあげてください。
最低限で。cat /dev/smd7をループで舐めるやつと、コマンドを投げるやつを分けてみた。
けどなんかうまく動いてない時がある。。。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
AndroidAtCommandUITheme {
MainScreen()
}
}
}
}
@Composable
private fun MainScreen() {
val scope = rememberCoroutineScope()
val outputList = remember { mutableStateOf(emptyList<String>()) }
val commandText = remember { mutableStateOf("AT") }
/** AT コマンドを投げる */
fun executeCommand() {
scope.launch(Dispatchers.IO) {
// 出力は outputList で
Runtime.getRuntime().exec(
arrayOf("su", "-c", "echo", "-e", """ "${commandText.value}\r" """, ">", "/dev/smd7")
)
}
}
// AT コマンドの出力を while ループで取り出す
LaunchedEffect(key1 = Unit) {
withContext(Dispatchers.IO) {
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", "cat", "/dev/smd7"))
launch {
// 出力を取り出す
try {
process.inputStream.bufferedReader().use { bufferedReader ->
while (isActive) {
val readText = bufferedReader.readLine()?.ifEmpty { null } ?: continue
outputList.value += readText
}
}
} catch (e: Exception) {
// 握りつぶす
}
}
// cat を終わらせる
try {
awaitCancellation()
} finally {
process.destroy()
}
}
}
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(modifier = Modifier.padding(innerPadding)) {
Row(
modifier = Modifier.padding(10.dp),
horizontalArrangement = Arrangement.spacedBy(5.dp),
verticalAlignment = Alignment.CenterVertically
) {
OutlinedTextField(
modifier = Modifier.weight(1f),
value = commandText.value,
onValueChange = { commandText.value = it },
singleLine = true,
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Go,
keyboardType = KeyboardType.Ascii
),
keyboardActions = KeyboardActions(onGo = { executeCommand() }),
label = { Text(text = "AT コマンド") }
)
Button(onClick = { executeCommand() }) {
Text(text = "実行")
}
}
LazyColumn {
items(outputList.value) { output ->
Text(
modifier = Modifier.fillMaxWidth(),
text = output
)
HorizontalDivider(color = LocalContentColor.current.copy(alpha = 0.05f))
}
}
}
}
}こんな感じです。
下に積まれていくのでスクロールしないといけない。
AT コマンド、マジで情報がないので時間を無駄にした間が半端ない。
これならlogcat -b radioのログでも眺めてたほうがまだ有意義です。