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

原文地址:https://www.cnblogs.com/kelisi-king/p/14677939.html