dubai: Disable 5G when front camera is in use

On some network(s) (confirmed on Jio), the usage of 5G kills front
camera and crashes the camera app. Logs reveal hardware or firmware
issues related to interference or bandwidth, which is out of my
expertise:

[   63.301897] CAM_ERR: CAM-ISP: cam_ife_csid_irq: 5016 CSID:2 RX_ERROR_LANE0_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:300000000Hz

Until this can be actually fixed (if ever), a temporary workaround.

Inspired by a860cc8189

Change-Id: Ifefb36cf113a5f25feda771ea7729418553e74ed
This commit is contained in:
Adithya R 2023-05-31 15:41:06 +05:30 committed by Marc Bourgoin
parent ee1e29f6b9
commit 8808e9b818
6 changed files with 243 additions and 0 deletions

22
camera/Android.bp Normal file
View file

@ -0,0 +1,22 @@
//
// Copyright (C) 2023 ArrowOS
//
// SPDX-License-Identifier: Apache-2.0
//
android_app {
name: "DubaiCameraService",
srcs: ["src/**/*.java"],
certificate: "platform",
platform_apis: true,
privileged: true,
system_ext_specific: true,
required: ["privapp-permissions-dubaicameraservice.xml"],
}
prebuilt_etc {
name: "privapp-permissions-dubaicameraservice.xml",
src: "privapp-permissions-dubaicameraservice.xml",
system_ext_specific: true,
sub_dir: "permissions",
}

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 ArrowOS
SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arrow.dubaicameraservice"
android:sharedUserId="android.uid.system">
<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.MODIFY_PHONE_STATE" />
<application
android:label="DubaiCameraService"
android:persistent="true">
<receiver
android:name=".BootReceiver"
android:exported="false">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service android:name=".DubaiCameraService"
android:permission="DubaiCameraService"
android:exported="false">
</service>
</application>
</manifest>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 ArrowOS
SPDX-License-Identifier: Apache-2.0
-->
<permissions>
<privapp-permissions package="com.arrow.dubaicameraservice">
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
</privapp-permissions>
</permissions>

View file

@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 ArrowOS
*
* SPDX-License-Identifier: Apache-2.0
*/
package com.arrow.dubaicameraservice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
return;
DubaiCameraService.startService(context);
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (C) 2023 ArrowOS
*
* SPDX-License-Identifier: Apache-2.0
*/
package com.arrow.dubaicameraservice;
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.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.Log;
import java.util.concurrent.Executor;
public class DubaiCameraService extends Service {
private static final boolean DEBUG = false;
private static final String TAG = "DubaiCameraService";
private static final String FRONT_CAMERA_ID = "1";
private CameraManager mCameraManager;
private SubscriptionManager mSubManager;
private TelephonyManager mTelephonyManager;
private boolean mIsFrontCamInUse = false;
private int mSubId = INVALID_SUBSCRIPTION_ID;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Executor mExecutor = new HandlerExecutor(mHandler);
private final CameraManager.AvailabilityCallback mCameraCallback =
new CameraManager.AvailabilityCallback() {
@Override
public void onCameraAvailable(String cameraId) {
dlog("onCameraAvailable id:" + cameraId);
if (cameraId.equals(FRONT_CAMERA_ID)) {
mIsFrontCamInUse = false;
update5gState();
}
}
@Override
public void onCameraUnavailable(String cameraId) {
dlog("onCameraUnavailable id:" + cameraId);
if (cameraId.equals(FRONT_CAMERA_ID)) {
mIsFrontCamInUse = true;
update5gState();
}
}
};
private final SubscriptionManager.OnSubscriptionsChangedListener mSubListener =
new SubscriptionManager.OnSubscriptionsChangedListener() {
@Override
public void onSubscriptionsChanged() {
dlog("onSubscriptionsChanged");
update5gState();
}
};
private class ActiveDataSubIdCallback extends TelephonyCallback implements
TelephonyCallback.ActiveDataSubscriptionIdListener {
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
dlog("onActiveDataSubscriptionIdChanged subId:" + subId);
mSubId = subId;
update5gState();
}
};
private final TelephonyCallback mTelephonyCallback = new ActiveDataSubIdCallback();
@Override
public void onCreate() {
dlog("onCreate");
mCameraManager = getSystemService(CameraManager.class);
mSubManager = getSystemService(SubscriptionManager.class);
mTelephonyManager = getSystemService(TelephonyManager.class);
mCameraManager.registerAvailabilityCallback(mCameraCallback, mHandler);
mTelephonyManager.registerTelephonyCallback(mExecutor, mTelephonyCallback);
mSubManager.addOnSubscriptionsChangedListener(mExecutor, mSubListener);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
dlog("onStartCommand");
return START_STICKY;
}
@Override
public void onDestroy() {
dlog("onDestroy");
mCameraManager.unregisterAvailabilityCallback(mCameraCallback);
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
mSubManager.removeOnSubscriptionsChangedListener(mSubListener);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
public static void startService(Context context) {
Log.i(TAG, "Starting service");
context.startServiceAsUser(new Intent(context, DubaiCameraService.class),
UserHandle.CURRENT);
}
private void update5gState() {
if (mSubId == INVALID_SUBSCRIPTION_ID
|| mSubManager.getActiveSubscriptionIdList().length <= 0) {
dlog("update5gState: Invalid subid or no active subs!");
return;
}
final TelephonyManager tm = mTelephonyManager.createForSubscriptionId(mSubId);
// Arguably we should use ALLOWED_NETWORK_TYPES_REASON_POWER here but that's already
// used by battery saver, and we are out of other reasons
long allowedNetworkTypes = tm.getAllowedNetworkTypesForReason(
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 {
return;
}
tm.setAllowedNetworkTypesForReason(ALLOWED_NETWORK_TYPES_REASON_CARRIER,
allowedNetworkTypes);
}
private static void dlog(String msg) {
if (DEBUG) Log.d(TAG, msg);
}
}

View file

@ -55,6 +55,7 @@ PRODUCT_COPY_FILES += \
# Camera # Camera
PRODUCT_PACKAGES += \ PRODUCT_PACKAGES += \
DubaiCameraService \
libgui_shim_vendor libgui_shim_vendor
# Fingerprint # Fingerprint