MotoNrEnabler: Add a service to enable 5G via OEM RIL request

Clearing and rebuilding modem cache (e.g. mdmddr, mdm1m9kefs1,
mdm1m9kefs2, carrier, and ddr partitions for MDM devices) is typically
necessary after modem firmware upgrade. However, NR is disabled in
Moto's modem firmware by default, so choosing NR results in "No signal"
after rebuilding modem cache with custom ROMs installed. Users have to
go back to stock once to make it work again, which is a huge pain.

It's observed that stock ROMs control NR via a custom RIL request, and
choose it based on carrier config and user preference (yes they have a
toggle in system settings) after SIM provisioning. Here, we implement a
service to automatically enable NR and DSS in the same approach, so
that users no longer need to go back to stock after upgrading modem
firmware. The implementation is based on telephony-common.jar,
qti-telephony-common.jar and qcom-moto-telephony-ext.jar from nio.
You're suggested to check if the magic numbers and payload formats
match your device's stock ROM before using this service.

Change-Id: I5ecfae93717fe87e6b1c1a75caa674b466403391
This commit is contained in:
dianlujitao 2024-01-12 22:33:52 +08:00
parent 0847f2dbca
commit 42a4d5f209
11 changed files with 739 additions and 0 deletions

18
MotoNrEnabler/Android.bp Normal file
View File

@ -0,0 +1,18 @@
//
// SPDX-FileCopyrightText: 2024 The LineageOS Project
// SPDX-License-Identifier: Apache-2.0
//
android_app {
name: "MotoNrEnabler",
srcs: [
"src/**/*.aidl",
"src/**/*.kt",
],
libs: ["telephony-common"],
certificate: "platform",
platform_apis: true,
system_ext_specific: true,
}

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-FileCopyrightText: 2024 The LineageOS Project
SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.lineageos.motorola.nrenabler"
android:sharedUserId="android.uid.phone">
<uses-permission android:name="com.qualcomm.permission.USE_QCRIL_MSG_TUNNEL" />
<application
android:label="MotoNrEnabler"
android:persistent="true"
android:directBootAware="true">
<service
android:name=".NrEnablerService" />
<receiver
android:name=".BootCompletedReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@ -0,0 +1,5 @@
package com.qualcomm.qcrilmsgtunnel;
interface IQcrilMsgTunnel {
int sendOemRilRequestRaw(in byte[] request, out byte[] response, in int sub);
}

View File

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.lineageos.motorola.nrenabler
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
class BootCompletedReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d(TAG, "Starting")
context.startService(Intent(context, NrEnablerService::class.java))
}
companion object {
private const val TAG = "MotoNrEnabler"
}
}

View File

@ -0,0 +1,94 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.lineageos.motorola.nrenabler
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Handler
import android.os.IBinder
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.util.Log
import java.util.concurrent.atomic.AtomicBoolean
class NrEnablerService : Service() {
private lateinit var motoExtService: QcomMotoExtTelephonyService
private val handler by lazy { Handler(mainLooper) }
private val workingInProgress = AtomicBoolean(false)
private val repeatWorkOnNRModeAndDSSIfFail = object : Runnable {
override fun run() {
if (workingInProgress.getAndSet(true))
return
if (!workOnNRModeAndDSS()) {
Log.v(TAG, "workOnNRModeAndDSS failed, retry after 5s")
handler.removeCallbacks(this)
handler.postDelayed(this, 5000)
}
workingInProgress.set(false)
}
}
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (!workingInProgress.get()) {
handler.post(repeatWorkOnNRModeAndDSSIfFail)
}
}
}
override fun onCreate() {
motoExtService = QcomMotoExtTelephonyService(this)
registerReceiver(
broadcastReceiver, IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
)
}
private fun workOnNRModeAndDSS(): Boolean {
val activeSubs =
getSystemService(SubscriptionManager::class.java)?.getActiveSubscriptionInfoList()
if (activeSubs.isNullOrEmpty()) {
Log.v(TAG, "workOnNRModeAndDSS: no active sub.")
return true
}
for (aSubInfo in activeSubs) {
val phoneId = SubscriptionManager.getPhoneId(aSubInfo.subscriptionId)
if (!validatePhoneId(phoneId)) {
Log.e(TAG, "Invalid phoneId: $phoneId")
return false
}
// Moto sets them based on carrier config, but we unconditionally
// enable NR and DSS here because maintaining carrier config is
// intractable for us.
Log.v(TAG, "workOnNRModeAndDSS: setNrModeDisabled for phone ${phoneId}")
if (!motoExtService.setNrModeDisabled(phoneId, NrMode.AUTO)) {
return false
}
Log.v(TAG, "workOnNRModeAndDSS: setDSSEnabled for phone ${phoneId}")
if (!motoExtService.setDSSEnabled(phoneId, 1.toByte())) {
return false
}
}
return true
}
private fun validatePhoneId(phoneId: Int): Boolean {
val phoneCount = getSystemService(TelephonyManager::class.java).activeModemCount
return phoneId in 0 until phoneCount
}
override fun onBind(intent: Intent?): IBinder? = null
companion object {
private const val TAG = "MotoNrEnabler"
}
}

View File

@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.lineageos.motorola.nrenabler
enum class NrMode(private val id: Int) {
AUTO(0),
DISABLE_SA(1),
DISABLE_NSA(2);
fun toInt(): Int {
return id
}
companion object {
fun fromInt(id: Int): NrMode? {
for (en in NrMode.values()) {
if (en.id == id) {
return en
}
}
return null
}
}
}

View File

@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.lineageos.motorola.nrenabler
import android.content.Context
import android.util.Log
import com.android.internal.telephony.PhoneFactory
import java.nio.ByteBuffer
class QcomMotoExtTelephonyService(private val context: Context) {
private val qcrilMsgTunnelConnector = QcrilMsgTunnelConnector(context)
fun setNrModeDisabled(phoneId: Int, mode: NrMode): Boolean {
val nrModeInModem = getNrModeDisabled(phoneId)
Log.v(TAG, "nrModeInModem = $nrModeInModem")
if (mode == nrModeInModem) {
Log.d(
TAG,
"setNrModeDisabled equals nrModeInModem:$nrModeInModem, ignore set for phoneID:$phoneId"
)
return true
}
val data = ByteArray(9)
val buf = ByteBuffer.wrap(data)
buf.order(QcomOemConstants.getByteOrderByRequestId(QcomOemConstants.OEM_RIL_REQUEST_SET_NR_DISABLE_MODE))
buf.putInt(QcomOemConstants.OEM_RIL_REQUEST_SET_NR_DISABLE_MODE).putInt(1)
.put(mode.toInt().toByte())
return qcrilMsgTunnelConnector.invokeOemRilRequestRawForPhone(phoneId, data, null) >= 0
}
private fun getNrModeDisabled(phoneId: Int): NrMode? {
val data = ByteArray(8)
val respData = ByteArray(1)
val buf = ByteBuffer.wrap(data)
buf.order(QcomOemConstants.getByteOrderByRequestId(QcomOemConstants.OEM_RIL_REQUEST_GET_NR_DISABLE_MODE))
buf.putInt(QcomOemConstants.OEM_RIL_REQUEST_GET_NR_DISABLE_MODE)
if (qcrilMsgTunnelConnector.invokeOemRilRequestRawForPhone(phoneId, data, respData) >= 0) {
return NrMode.fromInt(respData[0].toInt())
}
return null
}
private fun getDSSEnabled(phoneId: Int): Byte {
val rdeNv =
qcrilMsgTunnelConnector.getRdeNvValueByElementId(phoneId, QcomNvInfo.RDE_EFS_DSS_I)
return (rdeNv?.dataObj as QcomNvInfo.NvGenericDataType?)?.data?.get(0) ?: 2.toByte()
}
fun setDSSEnabled(phoneId: Int, enabled: Byte): Boolean {
val prev = getDSSEnabled(phoneId)
Log.v(TAG, "previous DSS mode = $prev")
if (prev == enabled) {
Log.d(TAG, "Skip setDSSEnabled as no change.")
return true
}
return qcrilMsgTunnelConnector.setRdeNvValue(phoneId, QcomNvInfo.RDE_EFS_DSS_I, enabled)
}
companion object {
private const val TAG = "MotoNrEnabler: QcomMotoExtTelephonyService"
}
}

View File

@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.lineageos.motorola.nrenabler
import android.util.Log
import java.nio.ByteBuffer
import java.nio.ByteOrder
object QcomNvInfo {
private const val TAG = "MotoNrEnabler: QcomNvInfo"
const val RDE_EFS_DSS_I = 10030
interface NvDataType {
fun serialize(buf: ByteBuffer)
fun size(): Int
}
class RdeNvValue {
var elementId = 0
var recordNum = 0
var offset = 0
var length = 0
var dataObj: NvDataType? = null
val size: Int
get() {
return (dataObj?.size() ?: 1) + 16
}
}
class NvGenericDataType : NvDataType {
var data: ByteArray? = null
constructor()
constructor(byte: Byte) {
data = byteArrayOf(byte)
}
override fun serialize(buf: ByteBuffer) {
data?.let {
buf.put(it)
}
}
override fun size(): Int {
return data?.size ?: 0
}
}
fun getRdeByteOrder(): ByteOrder {
return QcomOemConstants.getByteOrderByRequestId(QcomOemConstants.OEM_RIL_REQUEST_CDMA_GET_RDE_ITEM)
}
fun getRdeNvName(elementId: Int): String {
return when (elementId) {
RDE_EFS_DSS_I -> "RDE_EFS_DSS_I"
else -> {
Log.w(TAG, "unknown RDE element ID: $elementId")
""
}
}
}
}

View File

@ -0,0 +1,217 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.lineageos.motorola.nrenabler
import android.util.Log
import java.nio.BufferUnderflowException
import java.nio.ByteBuffer
object QcomNvUtils {
private const val TAG = "MotoNrEnabler: QcomNvUtils"
private const val DEFAULT_SPC_CODE = "000000"
private const val READING_RDE_RESP_BUF_SIZE = 6144
private const val WRITING_RESP_BUF_SIZE = 2048
data class OemHookDataHeader(
val reqId: Int,
val dataLength: Int,
val error: OemHookRespError,
) {
val spcLockCode = ByteArray(6)
override fun toString(): String {
return "reqId = $reqId dataLength = $dataLength error = $error spcLockCode = ${
byteArrToStringLog(
spcLockCode
)
}"
}
companion object {
const val SIZE = 18
}
}
fun readOemHookRespHeader(reqId: Int, bytes: ByteArray?): OemHookDataHeader? {
return bytes?.let {
readOemHookRespHeader(
ByteBuffer.wrap(it).order(QcomOemConstants.getByteOrderByRequestId(reqId))
)
}
}
private fun readOemHookRespHeader(buf: ByteBuffer): OemHookDataHeader? {
return try {
val header = OemHookDataHeader(
buf.getInt(),
buf.getInt(),
OemHookRespError.fromInt(buf.getInt()),
)
for (i in 0 until header.spcLockCode.size) {
header.spcLockCode[i] = buf.get()
}
Log.d(TAG, "readOemHookRespHeader: $header")
header
} catch (e: BufferUnderflowException) {
Log.w(TAG, "decode RespHeader exception, BufferUnderflowException")
null
}
}
fun getReadingRdeNvReqData(rdeNv: QcomNvInfo.RdeNvValue): ByteArray {
return allocateRdeOemReqData(
QcomOemConstants.OEM_RIL_REQUEST_CDMA_GET_RDE_ITEM, rdeNv, DEFAULT_SPC_CODE
)
}
fun getWritingRdeNvReqData(rdeNv: QcomNvInfo.RdeNvValue): ByteArray {
return allocateRdeOemReqData(
QcomOemConstants.OEM_RIL_REQUEST_CDMA_SET_RDE_ITEM, rdeNv, DEFAULT_SPC_CODE
)
}
private fun allocateRdeOemReqData(
reqId: Int, rdeNv: QcomNvInfo.RdeNvValue, spcCode: String
): ByteArray {
val buf = ByteBuffer.allocate(rdeNv.size + OemHookDataHeader.SIZE)
buf.order(QcomNvInfo.getRdeByteOrder())
writeOemHookReqHeader(
buf, reqId, rdeNv.size, OemHookRespError.OEM_RIL_CDMA_SUCCESS, spcCode
)
buf.putInt(rdeNv.elementId)
buf.putInt(rdeNv.recordNum)
buf.putInt(rdeNv.offset)
rdeNv.dataObj.let {
if (it != null) {
buf.putInt(it.size())
it.serialize(buf)
} else {
buf.putInt(0)
buf.put(0.toByte())
}
}
val data = buf.array()
Log.d(
TAG,
"RDE request for element: ${QcomNvInfo.getRdeNvName(rdeNv.elementId)} Allocated OemReqData: data = ${
byteArrToStringLog(
data
)
}"
)
return data
}
fun allocateReadingRdeNvRespBuffer(): ByteArray {
return ByteArray(READING_RDE_RESP_BUF_SIZE)
}
fun allocateWritingRdeNvRespBuffer(): ByteArray {
return ByteArray(WRITING_RESP_BUF_SIZE)
}
fun decodeReadingRdeNvResult(resultData: ByteArray?): QcomNvInfo.RdeNvValue? {
if (resultData == null) {
return null
}
val buf = ByteBuffer.wrap(resultData).order(QcomNvInfo.getRdeByteOrder())
return try {
val header = readOemHookRespHeader(buf)
if (header != null && header.error === OemHookRespError.OEM_RIL_CDMA_SUCCESS) {
return deserializeRde(buf)
}
Log.w(TAG, "decodeReadingRdeNv get error for head")
null
} catch (e: BufferUnderflowException) {
Log.e(TAG, "decodeReadingRdeNvResult: buffer underflow")
null
}
}
private fun deserializeRde(buf: ByteBuffer): QcomNvInfo.RdeNvValue {
val rdeNv = QcomNvInfo.RdeNvValue()
rdeNv.elementId = buf.getInt()
rdeNv.recordNum = buf.getInt()
rdeNv.offset = buf.getInt()
rdeNv.length = buf.getInt()
Log.d(TAG, "decoding response for ${QcomNvInfo.getRdeNvName(rdeNv.elementId)}")
when (rdeNv.elementId) {
QcomNvInfo.RDE_EFS_DSS_I -> {
if (rdeNv.length > 0) {
val nvData = QcomNvInfo.NvGenericDataType()
nvData.data = buf.array().copyOfRange(34, 34 + rdeNv.length)
rdeNv.dataObj = nvData
}
}
else -> Log.d(TAG, "deserialize unknown elementId (${rdeNv.elementId})")
}
return rdeNv
}
fun byteArrToStringLog(arr: ByteArray?): String {
if (arr == null || arr.isEmpty()) {
return "null"
}
val sb = StringBuilder()
for (i in arr) {
sb.append(String.format("%02X", i))
}
return sb.toString()
}
private fun writeOemHookReqHeader(
buf: ByteBuffer, reqId: Int, len: Int, err: OemHookRespError, spcLockCode: String
) {
writeOemHookReqHeader(buf, reqId, len, err, spcLockCode.toByteArray())
}
private fun writeOemHookReqHeader(
buf: ByteBuffer, reqId: Int, len: Int, err: OemHookRespError, spcLockCode: ByteArray
) {
buf.putInt(reqId)
buf.putInt(len)
buf.putInt(err.toInt())
for (i in spcLockCode) {
buf.put(i)
}
Log.d(
TAG,
"writeOemHookReqHeader: reqId = $reqId dataLength = $len error = $err spcLockCode = ${
byteArrToStringLog(
spcLockCode
)
}"
)
}
enum class OemHookRespError(private val id: Int) {
OEM_RIL_CDMA_SUCCESS(0),
OEM_RIL_CDMA_RADIO_NOT_AVAILABLE(1),
OEM_RIL_CDMA_NAM_READ_WRITE_FAILURE(2),
OEM_RIL_CDMA_NAM_PASSWORD_INCORRECT(3),
OEM_RIL_CDMA_NAM_ACCESS_COUNTER_EXCEEDED(4),
OEM_RIL_CDMA_GENERIC_FAILURE(5);
fun toInt(): Int {
return id
}
companion object {
fun fromInt(id: Int): OemHookRespError {
for (en in values()) {
if (en.id == id) {
return en
}
}
return OEM_RIL_CDMA_GENERIC_FAILURE
}
}
}
}

View File

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.lineageos.motorola.nrenabler
import android.util.Log
import java.nio.ByteOrder
object QcomOemConstants {
const val TAG = "MotoNrEnabler: QcomOemConstants"
private const val OEM_RIL_CDMA_MESSAGE_TYPE_CDMA = 33554432
const val OEM_RIL_REQUEST_GET_NR_DISABLE_MODE = 327752
const val OEM_RIL_REQUEST_SET_NR_DISABLE_MODE = 327753
const val OEM_RIL_REQUEST_CDMA_SET_RDE_ITEM = 33554453
const val OEM_RIL_REQUEST_CDMA_GET_RDE_ITEM = 33554454
fun getByteOrderByRequestId(reqId: Int): ByteOrder {
return if (reqId >= OEM_RIL_CDMA_MESSAGE_TYPE_CDMA) {
ByteOrder.LITTLE_ENDIAN
} else ByteOrder.BIG_ENDIAN
}
fun getRequestName(reqId: Int): String {
return when (reqId) {
OEM_RIL_REQUEST_CDMA_SET_RDE_ITEM -> "OEM_RIL_REQUEST_CDMA_SET_RDE_ITEM"
OEM_RIL_REQUEST_CDMA_GET_RDE_ITEM -> "OEM_RIL_REQUEST_CDMA_GET_RDE_ITEM"
else -> {
Log.w(TAG, "unknown request ID: $reqId")
""
}
}
}
}

View File

@ -0,0 +1,161 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.lineageos.motorola.nrenabler
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Handler
import android.os.IBinder
import android.os.RemoteException
import android.util.Log
import com.android.internal.telephony.uicc.IccUtils
import com.qualcomm.qcrilmsgtunnel.IQcrilMsgTunnel
class QcrilMsgTunnelConnector(private val context: Context) {
private val handler = Handler(context.mainLooper)
private var qcrilMsgService: IQcrilMsgTunnel? = null
private val qcrilMsgTunnelConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
Log.d(TAG, "QcrilMsgTunnel Service connected")
qcrilMsgService = IQcrilMsgTunnel.Stub.asInterface(service)
if (qcrilMsgService == null) {
Log.e(TAG, "QcrilMsgTunnelService Connect Failed (onServiceConnected)")
return
}
service.linkToDeath(qcrilMsgServiceDeathRecipient, 0)
}
override fun onServiceDisconnected(name: ComponentName) {
Log.e(TAG, "The connection to the service got disconnected unexpectedly!")
qcrilMsgService = null
}
}
private val qcrilMsgServiceDeathRecipient = IBinder.DeathRecipient {
Log.e(TAG, "QcrilMsgService Died")
context.unbindService(qcrilMsgTunnelConnection)
handler.postDelayed({ bindToQcrilMsgTunnelService() }, 4000)
}
init {
bindToQcrilMsgTunnelService()
}
private fun bindToQcrilMsgTunnelService() {
val intent = Intent()
intent.setClassName(QCRIL_MSG_TUNNEL_PACKAGE_NAME, QCRIL_MSG_TUNNEL_SERVICE_NAME)
Log.d(TAG, "Starting QcrilMsgTunnel Service")
context.bindService(intent, qcrilMsgTunnelConnection, Context.BIND_AUTO_CREATE)
}
fun invokeOemRilRequestRawForPhone(phoneId: Int, oemReq: ByteArray?, oemResp: ByteArray?): Int {
return qcrilMsgService?.let {
Log.d(
TAG, "invokeOemRilRequestRawForSubscriber: phoneId = $phoneId oemReq = ${
IccUtils.bytesToHexString(
oemReq
)
}"
)
val rspData = oemResp ?: ByteArray(1)
try {
val ret = it.sendOemRilRequestRaw(oemReq, rspData, phoneId)
Log.d(
TAG, "invokeOemRilRequestRawForSubscriber: phoneId = $phoneId oemResp = ${
IccUtils.bytesToHexString(rspData)
}"
)
ret
} catch (e: RemoteException) {
Log.e(TAG, "sendOemRilRequestRaw: Runtime Exception")
-1
}
} ?: run {
Log.e(TAG, "QcrilMsgTunnel Service not connected")
-1
}
}
private fun getRdeNvValueByElementId(
phoneId: Int, rdeElementId: Int, recordNum: Int
): QcomNvInfo.RdeNvValue? {
if (rdeElementId < 0) {
return null
}
val rdeNv = QcomNvInfo.RdeNvValue()
rdeNv.elementId = rdeElementId
rdeNv.recordNum = recordNum
val reqRdeData: ByteArray = QcomNvUtils.getReadingRdeNvReqData(rdeNv)
val respRdeData: ByteArray = QcomNvUtils.allocateReadingRdeNvRespBuffer()
return if (invokeOemRilRequestRawForPhone(
phoneId, reqRdeData, respRdeData
) < 0
) {
null
} else QcomNvUtils.decodeReadingRdeNvResult(respRdeData)
}
fun getRdeNvValueByElementId(phoneId: Int, rdeElementId: Int): QcomNvInfo.RdeNvValue? {
return getRdeNvValueByElementId(phoneId, rdeElementId, 0)
}
fun setRdeNvValue(phoneId: Int, rdeElementId: Int, value: Byte): Boolean {
val data = QcomNvInfo.NvGenericDataType(value)
return setRdeNvValue(phoneId, rdeElementId, data)
}
private fun setRdeNvValue(
phoneId: Int, rdeElementId: Int, nvData: QcomNvInfo.NvDataType
): Boolean {
return setRdeNvValue(phoneId, rdeElementId, 0, nvData)
}
private fun setRdeNvValue(
phoneId: Int, rdeElementId: Int, rdeRecordNum: Int, nvData: QcomNvInfo.NvDataType
): Boolean {
val nv = QcomNvInfo.RdeNvValue()
nv.elementId = rdeElementId
nv.recordNum = rdeRecordNum
nv.dataObj = nvData
return setRdeNvValue(phoneId, nv)
}
private fun setRdeNvValue(phoneId: Int, nv: QcomNvInfo.RdeNvValue): Boolean {
val reqData: ByteArray = QcomNvUtils.getWritingRdeNvReqData(nv)
val respData: ByteArray = QcomNvUtils.allocateWritingRdeNvRespBuffer()
return getWritingRdeNvRespResult(phoneId, reqData, respData)
}
private fun getWritingRdeNvRespResult(
phoneId: Int, reqData: ByteArray, respData: ByteArray
): Boolean {
return getWritingNvRespResult(
phoneId, QcomOemConstants.OEM_RIL_REQUEST_CDMA_SET_RDE_ITEM, reqData, respData
)
}
private fun getWritingNvRespResult(
phoneId: Int, reqId: Int, reqData: ByteArray, respData: ByteArray
): Boolean {
if (invokeOemRilRequestRawForPhone(phoneId, reqData, respData) < 0) {
return false
}
val respHeader = QcomNvUtils.readOemHookRespHeader(reqId, respData) ?: return false
Log.d(
TAG, "get Writing NV result for ${QcomOemConstants.getRequestName(respHeader.reqId)}"
)
return respHeader.error == QcomNvUtils.OemHookRespError.OEM_RIL_CDMA_SUCCESS
}
companion object {
private const val TAG = "MotoNrEnabler: QcrilMsgTunnelConnector"
private const val QCRIL_MSG_TUNNEL_PACKAGE_NAME = "com.qualcomm.qcrilmsgtunnel"
private const val QCRIL_MSG_TUNNEL_SERVICE_NAME =
"com.qualcomm.qcrilmsgtunnel.QcrilMsgTunnelService"
}
}