Android 多进程引发的一次crash
问题现象:
应用内操作后出现空指针异常
问题日志:
1 FATAL EXCEPTION: main 2 04-19 10:46:15.507 E/AndroidRuntime(23919): Process: com.test.test:remote, PID: 23919 3 04-19 10:46:15.507 E/AndroidRuntime(23919): java.lang.RuntimeException: Error receiving broadcast Intent { act=android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT cat=[android.bluetooth.headset.intent.category.companyid.85] flg=0x10 (has extras) } in com.xupin.poclibrary.tool.bluetooth.BluetoothManager$2@256db6d 4 04-19 10:46:15.507 E/AndroidRuntime(23919): at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1712) 5 04-19 10:46:15.507 E/AndroidRuntime(23919): at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2) 6 04-19 10:46:15.507 E/AndroidRuntime(23919): at android.os.Handler.handleCallback(Handler.java:883) 7 04-19 10:46:15.507 E/AndroidRuntime(23919): at android.os.Handler.dispatchMessage(Handler.java:100) 8 04-19 10:46:15.507 E/AndroidRuntime(23919): at android.os.Looper.loop(Looper.java:238) 9 04-19 10:46:15.507 E/AndroidRuntime(23919): at android.app.ActivityThread.main(ActivityThread.java:7823) 10 04-19 10:46:15.507 E/AndroidRuntime(23919): at java.lang.reflect.Method.invoke(Native Method) 11 04-19 10:46:15.507 E/AndroidRuntime(23919): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:512) 12 04-19 10:46:15.507 E/AndroidRuntime(23919): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1017) 13 04-19 10:46:15.507 E/AndroidRuntime(23919): Caused by: java.lang.NullPointerException: Attempt to read from field 'com.test.test.tool.entity.SessionEntity com.test.test.services.TestServices.callingSession' on a null object reference 14 04-19 10:46:15.507 E/AndroidRuntime(23919): at com.test.test.tool.bluetooth.BluetoothManager.handlePttBtnDown(BluetoothManager.java:469) 15 04-19 10:46:15.507 E/AndroidRuntime(23919): at com.test.test.tool.bluetooth.BluetoothManager.access$300(BluetoothManager.java:42) 16 04-19 10:46:15.507 E/AndroidRuntime(23919): at com.test.test.tool.bluetooth.BluetoothManager$2.onReceive(BluetoothManager.java:521) 17 04-19 10:46:15.507 E/AndroidRuntime(23919): at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1677)
定位分析:
crash 发生在remote进程(百度地图服务进程),而且分析,应用正常启动后 TestServices 该单例不可能为空,且通过日志发现动态注册的监听器会触发两次。
解决:
添加主进程判断:
Copyed from Android Jetpack 中WorkManager库中的GreedyScheduler.java
public class ProcessUtil { private static final String TAG = "ProcessUtil"; public static boolean isMainProcess(Context context) { String packageName = context.getPackageName(); String processName = getProcessName(context); Log.d(TAG, "package name:" + packageName + " process name:" + processName); return TextUtils.equals(context.getPackageName(), getProcessName(context)); } @Nullable public static String getProcessName(Context context) { if (SDK_INT >= 28) { return Application.getProcessName(); } // Try using ActivityThread to determine the current process name. try { Class<?> activityThread = Class.forName( "android.app.ActivityThread", false, MyApplication.class.getClassLoader()); final Object packageName; if (SDK_INT >= 18) { Method currentProcessName = activityThread.getDeclaredMethod("currentProcessName"); currentProcessName.setAccessible(true); packageName = currentProcessName.invoke(null); } else { Method getActivityThread = activityThread.getDeclaredMethod( "currentActivityThread"); getActivityThread.setAccessible(true); Method getProcessName = activityThread.getDeclaredMethod("getProcessName"); getProcessName.setAccessible(true); packageName = getProcessName.invoke(getActivityThread.invoke(null)); } if (packageName instanceof String) { return (String) packageName; } } catch (Throwable exception) { Log.d("TAG", "Unable to check ActivityThread for processName", exception); } // Fallback to the most expensive way int pid = android.os.Process.myPid(); ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); if (am != null) { List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses(); if (processes != null && !processes.isEmpty()) { for (ActivityManager.RunningAppProcessInfo process : processes) { if (process.pid == pid) { return process.processName; } } } } return null; } }
参考文档
https://yuanfentiank789.github.io/2017/10/26/Android%E5%BA%94%E7%94%A8%E5%86%85%E5%A4%9A%E8%BF%9B%E7%A8%8B%E5%88%86%E6%9E%90%E5%92%8C%E7%A0%94%E7%A9%B6/
https://stackoverflow.com/questions/6954027/detecting-if-youre-in-the-main-process-or-the-remote-service-process-in-applica/36256085