记一次App中多进程初始化导致百度定位失效问题

1,211 阅读4分钟

一、背景

项目中用到了多个第三方的SDK,其中有些外部服务是需要在AndroidManifest中配置的,并且通过形如android:process=":remote"配置单独的进程。如百度定位,对应service配置如下:

<service
    android:name="com.baidu.location.f"
    android:enabled="true"
    android:exported="false"
    android:process=":remote" />

应用宝最近升级了App的信息安全政策,对于App中有访问过国外IP的行为,都会予以临时下架。项目中需要针对应用宝包渠道作特殊处理,将用到的国外第三方SDK去除。

为了项目整体维护方便,采用方案Android Gradle基于参数化配置实现差异化构建,配置完成并构建。

即,以应用宝渠道去掉Flurry为例,通过Gradle设置参数标识后,Flurry初始化等各相关调用方法中,采用了mock方式的空方法实现,并不依赖Flurry SDK。

构建完成后,接到线上用户反馈百度定位功能失效。


二、排查与解决

Android Gradle基于参数化配置实现差异化构建,方案本身已经比较成熟,项目中多处针对差异化的构建场景下都有所使用。构建完成后的安装包,也分别反编译并核验过最终的mock效果。

经调试发现,针对去掉Flurry的构建,在百度定位时不能如期取得定位结果,定位功能直接失效。

经排查,具体原因如下:

对于AndroidManifest中配置了多进程的service,App启动时会同时会启动对应进程,也就是说,此时除了App主进程外,还会对应有其他配置了的进程。并且,对自定义的Application而言,会分别多次实例化。Application的每次实例化,由于实在不同的进程中,相互之间是没关系的。

项目中针对不同的组件,如日志组件、Flurry等,在Application中初始化时,有着各自对进程的判断信息,如日志组件仅是针对App主进程中才初始化(做了专门的进程判断),Flurry则是针对所有进程都会初始化(没有做进程判断,至于为什么不做主进程判断,有其他方面考虑)。且Flurry的初始化是封装在特定的FlurryHelper类中,对上述的mock写法,FlurryHelper中为了输出对应日志,又用到了日志组件。

/**
 * mock Flurry工具类
 *
 */
public final class FlurryHelper {
    public static final String TAG = "FlurryUtil";

    public synchronized static void initFlurry(Context context, boolean innerProcess) {
        CLog.d(TAG, "flurry init...mock");
    }

    public static void onStart(Context context){
        CLog.d(TAG, "flurry onStart...mock");
    }

    public static void onEndSession(Context context){
        CLog.d(TAG, "flurry onEndSession...mock");
    }
}

于是,问题产生了,对于百度定位进程而言,无论是App一开始启动时,还是后续进行定位服务时,启动的百度定位进程,在执行Application初始化时,最终都调用到了mock写法中的FlurryHelper对应方法,而其中,日志组件是并未初始化的,导致百度定位进程事实上的运行时异常而终止。

Android官方的系统中,App中只要有进程发生未捕获异常,都会有运行时异常终止弹窗。当然了,对于集成第三方SDK的进程,虽然在当前App中有进程异常终止弹窗,但force stopping确认后,但并不影响对App中与此第三方SDK无关的功能使用。只是会让用户感觉有所困惑。

国内App手机厂商,一般都对此做了进一步优化。如集成第三方SDK的进程崩溃,往往都直接没有异常终止弹窗提示到用户。此时,对用户而言,App中非主进程的崩溃是无感知的。当然了,对应的功能还是会受到影响。

这也就解释了,App没有任何崩溃感知的情况下,百度定位功能却莫名失效了。


解决:

知道问题原因后,其实解决起来非常容易,直接将mock的FlurryHelper中的日志组件替换成Android原生日志类Log即可。


三、结语

项目中,往往都会有意无意中使用到多进程,尤其对应AndroidManifest中配置的多进程,是往往容易被忽略的。多进程在初始化时,会分别执行各自的Application实例的初始化。而Application初始化中,一般都会进行其他各组件等初始化。此时,需要确认清组件与进程之间的依赖关系。如有必要,组件初始化时需要进行进程判断。特别需要注意的是,在多进程场景下的组件间的依赖关系,以及对应的初始化先后顺序等。

国内的手机厂商,针对App中非主进程的崩溃,往往用户层面是无法感知的。但对应的功能依然会受到影响。因此,涉及到此类多进程时,需要格外小心。

end~