dubai: Disable only N78 5G SA band for front camera

We don't need to disable 5G entirely during front camera usage, because
apparently only N78 band in SA 5G (Jio) is affected. Lower bands, such
as N28, does not break front camera so let's just disable the offending
band via RIL OEM commands when front camera is active.

Reversed the band editing mechanism from stock qcom-moto-telephony-ext.
Inspired by 70eebccf64

Change-Id: I6ccb247a5d1b1521e1828304f5570269d9e3f221
This commit is contained in:
Adithya R 2023-06-22 10:49:31 +05:30 committed by Marc Bourgoin
parent 8808e9b818
commit b9046bddf1
5 changed files with 215 additions and 28 deletions

View file

@ -6,7 +6,10 @@
android_app { android_app {
name: "DubaiCameraService", name: "DubaiCameraService",
srcs: ["src/**/*.java"], srcs: [
"src/**/*.java",
"src/**/*.aidl",
],
certificate: "platform", certificate: "platform",
platform_apis: true, platform_apis: true,
privileged: true, privileged: true,

View file

@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="com.qualcomm.permission.USE_QCRIL_MSG_TUNNEL" />
<application <application
android:label="DubaiCameraService" android:label="DubaiCameraService"

View file

@ -7,8 +7,6 @@
package com.arrow.dubaicameraservice; package com.arrow.dubaicameraservice;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER;
import static android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_NR;
import android.app.Service; import android.app.Service;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@ -25,6 +23,7 @@ import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import java.util.Arrays;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
public class DubaiCameraService extends Service { public class DubaiCameraService extends Service {
@ -33,13 +32,16 @@ public class DubaiCameraService extends Service {
private static final String TAG = "DubaiCameraService"; private static final String TAG = "DubaiCameraService";
private static final String FRONT_CAMERA_ID = "1"; private static final String FRONT_CAMERA_ID = "1";
private static final int OFFENDING_NR_SA_BAND = 78;
private CameraManager mCameraManager; private CameraManager mCameraManager;
private SubscriptionManager mSubManager; private SubscriptionManager mSubManager;
private TelephonyManager mTelephonyManager; private TelephonyManager mTelephonyManager;
private QcRilMsgUtils mQcRilMsgUtils;
private boolean mIsFrontCamInUse = false; private boolean mIsFrontCamInUse = false;
private int mSubId = INVALID_SUBSCRIPTION_ID; private int[] mActiveSubIds = new int[0];
private int mDefaultDataSubId = INVALID_SUBSCRIPTION_ID;
private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Executor mExecutor = new HandlerExecutor(mHandler); private final Executor mExecutor = new HandlerExecutor(mHandler);
@ -70,7 +72,13 @@ public class DubaiCameraService extends Service {
@Override @Override
public void onSubscriptionsChanged() { public void onSubscriptionsChanged() {
dlog("onSubscriptionsChanged"); dlog("onSubscriptionsChanged");
update5gState(); final int[] subs = mSubManager.getActiveSubscriptionIdList();
if (!Arrays.equals(subs, mActiveSubIds)) {
dlog("active subs changed, was: " + Arrays.toString(mActiveSubIds)
+ ", now: " + Arrays.toString(subs));
mActiveSubIds = subs;
update5gState();
}
} }
}; };
@ -79,8 +87,10 @@ public class DubaiCameraService extends Service {
@Override @Override
public void onActiveDataSubscriptionIdChanged(int subId) { public void onActiveDataSubscriptionIdChanged(int subId) {
dlog("onActiveDataSubscriptionIdChanged subId:" + subId); dlog("onActiveDataSubscriptionIdChanged subId:" + subId);
mSubId = subId; if (subId != mDefaultDataSubId) {
update5gState(); mDefaultDataSubId = subId;
update5gState();
}
} }
}; };
@ -89,24 +99,26 @@ public class DubaiCameraService extends Service {
@Override @Override
public void onCreate() { public void onCreate() {
dlog("onCreate"); dlog("onCreate");
mQcRilMsgUtils = new QcRilMsgUtils(this);
mCameraManager = getSystemService(CameraManager.class); mCameraManager = getSystemService(CameraManager.class);
mSubManager = getSystemService(SubscriptionManager.class); mSubManager = getSystemService(SubscriptionManager.class);
mTelephonyManager = getSystemService(TelephonyManager.class); mTelephonyManager = getSystemService(TelephonyManager.class);
mCameraManager.registerAvailabilityCallback(mCameraCallback, mHandler);
mTelephonyManager.registerTelephonyCallback(mExecutor, mTelephonyCallback);
mSubManager.addOnSubscriptionsChangedListener(mExecutor, mSubListener);
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
dlog("onStartCommand"); dlog("onStartCommand");
mQcRilMsgUtils.bindService();
mCameraManager.registerAvailabilityCallback(mCameraCallback, mHandler);
mTelephonyManager.registerTelephonyCallback(mExecutor, mTelephonyCallback);
mSubManager.addOnSubscriptionsChangedListener(mExecutor, mSubListener);
return START_STICKY; return START_STICKY;
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
dlog("onDestroy"); dlog("onDestroy");
mQcRilMsgUtils.unbindService();
mCameraManager.unregisterAvailabilityCallback(mCameraCallback); mCameraManager.unregisterAvailabilityCallback(mCameraCallback);
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
mSubManager.removeOnSubscriptionsChangedListener(mSubListener); mSubManager.removeOnSubscriptionsChangedListener(mSubListener);
@ -124,30 +136,22 @@ public class DubaiCameraService extends Service {
} }
private void update5gState() { private void update5gState() {
if (mSubId == INVALID_SUBSCRIPTION_ID if (mDefaultDataSubId == INVALID_SUBSCRIPTION_ID
|| mSubManager.getActiveSubscriptionIdList().length <= 0) { || mActiveSubIds.length == 0) {
dlog("update5gState: Invalid subid or no active subs!"); dlog("update5gState: Invalid subid or no active subs!");
return; return;
} }
final TelephonyManager tm = mTelephonyManager.createForSubscriptionId(mSubId); if (mQcRilMsgUtils.setNrSaBandEnabled(mSubManager.getPhoneId(mDefaultDataSubId),
// Arguably we should use ALLOWED_NETWORK_TYPES_REASON_POWER here but that's already OFFENDING_NR_SA_BAND, !mIsFrontCamInUse)) {
// used by battery saver, and we are out of other reasons Log.i(TAG, (mIsFrontCamInUse ? "Disabled" : "Enabled") + " NR SA band "
long allowedNetworkTypes = tm.getAllowedNetworkTypesForReason( + OFFENDING_NR_SA_BAND + " for subId " + mDefaultDataSubId);
ALLOWED_NETWORK_TYPES_REASON_CARRIER);
final boolean is5gAllowed = (allowedNetworkTypes & NETWORK_TYPE_BITMASK_NR) != 0;
dlog("update5gState mIsFrontCamInUse:" + mIsFrontCamInUse + " is5gAllowed:" + is5gAllowed);
if (mIsFrontCamInUse && is5gAllowed) {
allowedNetworkTypes &= ~NETWORK_TYPE_BITMASK_NR;
} else if (!mIsFrontCamInUse && !is5gAllowed) {
allowedNetworkTypes |= NETWORK_TYPE_BITMASK_NR;
} else { } else {
return; Log.e(TAG, "Failed to " + (mIsFrontCamInUse ? "disable" : "enable") + " NR SA band "
+ OFFENDING_NR_SA_BAND + " for subId " + mDefaultDataSubId);
} }
tm.setAllowedNetworkTypesForReason(ALLOWED_NETWORK_TYPES_REASON_CARRIER,
allowedNetworkTypes);
} }
private static void dlog(String msg) { protected static void dlog(String msg) {
if (DEBUG) Log.d(TAG, msg); if (DEBUG) Log.d(TAG, msg);
} }
} }

View file

@ -0,0 +1,168 @@
/*
* Copyright (C) 2023 ArrowOS
*
* SPDX-License-Identifier: Apache-2.0
*/
package com.arrow.dubaicameraservice;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.qualcomm.qcrilmsgtunnel.IQcrilMsgTunnel;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class QcRilMsgUtils {
private static final String TAG = "DubaiCameraService-QcRil";
private static final String PACKAGE_NAME = "com.qualcomm.qcrilmsgtunnel";
private static final String SERVICE_NAME = "com.qualcomm.qcrilmsgtunnel.QcrilMsgTunnelService";
private static final int OEM_RIL_REQUEST_GET_BAND_PREF = 327723;
private static final int OEM_RIL_REQUEST_SET_BAND_PREF = 327724;
private static final int BAND_CONFIG_LENGTH = 168;
private static final int LTE_CONFIG_LENGTH = 4;
private static final int NR_CONFIG_LENGTH = 8;
private IQcrilMsgTunnel mService;
private QcrilMsgTunnelConnection mServiceConnection;
private Context mContext;
public QcRilMsgUtils(Context context) {
mContext = context;
mServiceConnection = new QcrilMsgTunnelConnection();
}
protected void bindService() {
dlog("bindService");
if (!mContext.bindService(new Intent().setClassName(PACKAGE_NAME, SERVICE_NAME),
mServiceConnection, Context.BIND_AUTO_CREATE)) {
Log.e(TAG, "Failed to bind to QcrilMsgTunnelService!");
}
}
protected void unbindService() {
dlog("unbindService");
mContext.unbindService(mServiceConnection);
mService = null;
}
/* TODO: split this function */
protected boolean setNrSaBandEnabled(int phoneId, int band, boolean enabled) {
if (mService == null) {
Log.e(TAG, "setNrSaBandEnabled: mService is null!");
return false;
}
dlog("setNrSaBandEnabled: phoneId=" + phoneId + " band=" + band + " enabled=" + enabled);
// get band config
byte[] reqData = new byte[8];
ByteBuffer reqBuf = ByteBuffer.wrap(reqData)
.order(ByteOrder.BIG_ENDIAN)
.putInt(OEM_RIL_REQUEST_GET_BAND_PREF)
.putInt(0);
byte[] resp = new byte[BAND_CONFIG_LENGTH];
try {
int ret = mService.sendOemRilRequestRaw(reqData, resp, phoneId);
if (ret < 0)
throw new Exception();
} catch (Exception e) {
Log.e(TAG, "sendOemRilRequestRaw failed to get band config!", e);
return false;
}
ByteBuffer buf = ByteBuffer.wrap(resp)
.order(ByteOrder.nativeOrder());
long nasConfig = buf.getLong();
long[] lteConfigs = new long[LTE_CONFIG_LENGTH];
for (int i = 0; i < LTE_CONFIG_LENGTH; i++) {
lteConfigs[i] = buf.getLong();
}
long[] nrSaConfigs = new long[NR_CONFIG_LENGTH];
for (int i = 0; i < NR_CONFIG_LENGTH; i++) {
nrSaConfigs[i] = buf.getLong();
}
long[] nrNsaConfigs = new long[NR_CONFIG_LENGTH];
for (int i = 0; i < NR_CONFIG_LENGTH; i++) {
nrSaConfigs[i] = buf.getLong();
}
// modify band config
int row = (band - 1) / 64;
int col = (band - 1) % 64;
if (enabled) {
nrSaConfigs[row] |= (1 << col);
} else {
nrSaConfigs[row] &= ~(1 << col);
}
// set band config
byte[] newData = new byte[BAND_CONFIG_LENGTH + 8];
ByteBuffer newBuf = ByteBuffer.wrap(newData)
.order(ByteOrder.BIG_ENDIAN)
.putInt(OEM_RIL_REQUEST_SET_BAND_PREF)
.putInt(BAND_CONFIG_LENGTH)
.order(ByteOrder.nativeOrder())
.putLong(nasConfig);
for (int i = 0; i < LTE_CONFIG_LENGTH; i++) {
newBuf.putLong(lteConfigs[i]);
}
for (int i = 0; i < NR_CONFIG_LENGTH; i++) {
newBuf.putLong(nrSaConfigs[i]);
}
for (int i = 0; i < NR_CONFIG_LENGTH; i++) {
newBuf.putLong(nrNsaConfigs[i]);
}
try {
int ret = mService.sendOemRilRequestRaw(newData, new byte[1], phoneId);
if (ret < 0)
throw new Exception();
} catch (Exception e) {
Log.e(TAG, "sendOemRilRequestRaw failed to set band config!", e);
return false;
}
return true;
}
private class QcrilMsgTunnelConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IQcrilMsgTunnel.Stub.asInterface(service);
if (mService == null) {
Log.e(TAG, "Unable to get IQcrilMsgTunnel!");
return;
}
try {
service.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Log.e(TAG, "QcrilMsgTunnel service died, trying to bind again");
mService = null;
QcRilMsgUtils.this.bindService();
}
}, 0);
} catch (RemoteException e) {
Log.e(TAG, "linkToDeath failed", e);
}
Log.i(TAG, "QcrilMsgTunnel service connected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "QcrilMsgTunnel service disconnected");
mService = null;
}
}
private static void dlog(String msg) {
DubaiCameraService.dlog(msg);
}
}

View file

@ -0,0 +1,11 @@
package com.qualcomm.qcrilmsgtunnel;
interface IQcrilMsgTunnel {
/**
* Sends a OEM request to the RIL and returns the response back to the
* Caller. The returnValue is negative on failure. 0 or length of response on SUCCESS
*/
int sendOemRilRequestRaw(in byte[] request, out byte[] response, in int sub);
}