From 9f0ec9dcb23ccb9be77b0763a6a0726bc6a31c11 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sun, 10 May 2020 23:18:48 +0200 Subject: [PATCH] ModemConfig: Receive subId, resolve config and trigger modem FW flash Signed-off-by: Marijn Suijten --- ModemConfig/Android.bp | 11 ++ ModemConfig/AndroidManifest.xml | 18 ++ ModemConfig/README.md | 16 ++ .../modemconfig/ModemConfigReceiver.kt | 175 ++++++++++++++++++ README.md | 4 + 5 files changed, 224 insertions(+) create mode 100644 ModemConfig/Android.bp create mode 100644 ModemConfig/AndroidManifest.xml create mode 100644 ModemConfig/README.md create mode 100644 ModemConfig/src/com/sony/opentelephony/modemconfig/ModemConfigReceiver.kt diff --git a/ModemConfig/Android.bp b/ModemConfig/Android.bp new file mode 100644 index 0000000..248ab91 --- /dev/null +++ b/ModemConfig/Android.bp @@ -0,0 +1,11 @@ +android_app { + name: "ModemConfig", + certificate: "platform", + + proprietary: true, + privileged: true, + + srcs: ["src/**/*.kt"], + + sdk_version: "system_current", +} diff --git a/ModemConfig/AndroidManifest.xml b/ModemConfig/AndroidManifest.xml new file mode 100644 index 0000000..1d0f857 --- /dev/null +++ b/ModemConfig/AndroidManifest.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/ModemConfig/README.md b/ModemConfig/README.md new file mode 100644 index 0000000..14c03b7 --- /dev/null +++ b/ModemConfig/README.md @@ -0,0 +1,16 @@ +# ModemConfig + +Simple configurator that uses SIM information from `TelephonyManager` and a pre-extracted mapping to resolve to a configuration name, passed to the modem switcher which provisions the modem with the appropriate firmware. + +#### Updating the + +#### Testing: +Note that the subscription ID, passed in at the end, must be valid. + +```sh +am broadcast -n com.sony.opentelephony.modemconfig/.ModemConfigReceiver -a android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED --ei android.telephony.extra.SUBSCRIPTION_INDEX 1 +``` + +```sh +m ModemConfig && adb push out/target/product/bahamut/vendor/app/ModemConfig/ModemConfig.apk vendor/app/ModemConfig && adb shell killall com.sony.opentelephony.modemconfig; am broadcast -n com.sony.opentelephony.modemconfig/.ModemConfigReceiver -a android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED --ei android.telephony.extra.SUBSCRIPTION_INDEX 1 +``` diff --git a/ModemConfig/src/com/sony/opentelephony/modemconfig/ModemConfigReceiver.kt b/ModemConfig/src/com/sony/opentelephony/modemconfig/ModemConfigReceiver.kt new file mode 100644 index 0000000..2f86bcc --- /dev/null +++ b/ModemConfig/src/com/sony/opentelephony/modemconfig/ModemConfigReceiver.kt @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2020 Marijn Suijten + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.sony.opentelephony.modemconfig + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.telephony.SubscriptionManager +import android.telephony.TelephonyManager +import android.text.TextUtils +import android.util.Log +import org.xmlpull.v1.XmlPullParser + +private const val TAG = "ModemConfigReceiver" +private val newlineMatch = Regex("[\n\r]") + +class ModemConfigReceiver : BroadcastReceiver() { + private class ProviderFilter(val sim_config_id: String, + val mcc: String? = null, + val mnc: String? = null, + val gid1: String? = null, + val imsi: Regex? = null, + val sp: Regex? = null + ) { + override fun toString() = "[mcc: $mcc, mnc: $mnc, gid1: $gid1, imsi: ${imsi?.pattern}, " + + "sp: ${sp?.pattern}] => $sim_config_id" + } + + // TODO: Do a lateinit here? + private /*lateinit*/ var providers: List? = null + + private fun getProviders(context: Context): List { + if (providers != null) + return providers!! + + val list = arrayListOf() + + val currentMap = hashMapOf() + var simConfigId: String? = null + + // TODO: Kotlin .use {} block doesn't work here, while it does in regular apps... + /* +modemconfig/ModemConfigReceiver.kt:63:70: error: unresolved reference. None of the following + candidates is applicable because of receiver type mismatch: +@InlineOnly public inline fun ???.use(block: (???) -> ???): ??? + defined in kotlin.io +context.resources.getXml(R.xml.service_provider_sim_configs).use { + */ + val xml = context.resources.getXml(R.xml.service_provider_sim_configs) + try { + while (xml.next() != XmlPullParser.END_DOCUMENT) { + if (xml.eventType == XmlPullParser.END_TAG && + xml.name == "service_provider_sim_config") { + // When a node is closed, collect all elements and create a filter entry: + list.add(ProviderFilter( + simConfigId!!, + currentMap["mcc"], + currentMap["mnc"], + currentMap["gid1"], + currentMap["imsi"]?.let { Regex(it) }, + currentMap["sp"]?.let { Regex(it) } + )) + currentMap.clear() + continue + } + + if (xml.eventType != XmlPullParser.START_TAG) + continue + + if (xml.name == "service_provider_sim_config") { + // Start collection for this config id: + simConfigId = xml.getAttributeValue(null, "sim_config_id") + if (TextUtils.isEmpty(simConfigId)) + throw Exception("Unexpected empty sim_config_id attribute!") + currentMap.clear() + } else if (simConfigId != null) { + // If not in a service_provider_sim_config element, and a valid simConfigId + // /exists parse all members/subelements: + val text = cleanString(xml.nextText()) + if (currentMap.containsKey(xml.name)) + throw Exception("Already parsed ${xml.name}!") + currentMap[xml.name] = text + } + } + + } finally { + xml.close() + } + + providers = list + return list + } + + private fun cleanString(str: String) = str.replace(newlineMatch, "").trim() + + private fun findConfigurationName(context: Context, tm: TelephonyManager): String? { + val operator = tm.simOperator + val mcc = operator.substring(0, 3) + val mnc = operator.substring(3) + + val sp = cleanString(tm.simOperatorName) + + val imsi = tm.subscriberId + val gid1 = tm.groupIdLevel1 + val iccid2 = tm.simSerialNumber + + Log.d(TAG, "Matching providers against: $sp $mcc/$mnc, imsi: $imsi" + + ", gid: $gid1, iccid2: $iccid2") + + val result = getProviders(context).filter f@{ info -> + if (info.mcc != null && info.mcc != mcc) + return@f false + if (info.mnc != null && info.mnc != mnc) + return@f false + + if (info.gid1 != null && !gid1.startsWith(info.gid1)) + return@f false + + if (info.imsi != null && !info.imsi.matches(imsi)) + return@f false + + if (info.sp != null && !info.sp.matches(sp)) + return@f false + + true + } + + return if (result.isEmpty()) { + Log.w(TAG, "No matching config found") + null + } else { + if (result.size > 1) + Log.w(TAG, "Multiple matches found: ${result}, using last") + + val match = result.last() + Log.i(TAG, "Matched with $match") + match.sim_config_id + } + } + + override fun onReceive(context: Context, intent: Intent) { + Log.d(TAG, "Received intent! $intent") + if (SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED != intent.action) + throw Exception("Expected ${SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED}" + + ", got ${intent.action}. Is the intent filter correct??") + val subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID) + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + Log.d(TAG, "Received invalid subId. SIM removed?") + return + } + val slotIdx = SubscriptionManager.getSlotIndex(subId) // Can be INVALID_SIM_SLOT_INDEX + if (slotIdx == SubscriptionManager.INVALID_SIM_SLOT_INDEX) + throw Exception("Invalid slot index") + Log.d(TAG, "Finding configuration for subId $subId, slotIdx: $slotIdx") + + val globalTm = context.getSystemService(TelephonyManager::class.java) + val tm = globalTm!!.createForSubscriptionId(subId) + val name = findConfigurationName(context, tm) + } +} diff --git a/README.md b/README.md index a3c5999..e16b95e 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ # SonyOpenTelephony + +### ModemConfig + +Invokes modem-flasher with the appropriate firmware configuration name on boot and subscription (SIM) changes.