调用ActivityStarter.isAllowedToStart触发NullPointerException问题排查
小米/一加设备上startActivity触发系统进程NPE的原因分析
问题背景
近期有少量(用户数<10)小米、一加设备上的Android应用出现无法复现的崩溃,崩溃由调用startActivity(...)触发,实际异常在系统进程的ActivityStarter组件中抛出,崩溃栈如下:
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.android.server.wm.ConfigurationContainer.inPinnedWindowingMode()' on a null object reference at com.android.server.wm.ActivityStarter.isAllowedToStart(ActivityStarter.java:2068) at com.android.server.wm.ActivityStarter.startActivityInner(ActivityStarter.java:1874) at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1678) at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1231) at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:717)
核心疑点
- 崩溃调用栈显示
inPinnedWindowingMode()的调用位于ActivityStarter.java第2068行,但谷歌官方仓库中找不到对应行号的版本; - 谷歌官方代码中,
ActivityStarter里唯一调用inPinnedWindowingMode()的代码同时调用了同一对象的isUidPresent(),但异常中并未触发该方法的空指针:
boolean blockBalInTask = (newTask || !targetTask.isUidPresent(mCallingUid) || (LAUNCH_SINGLE_INSTANCE == mLaunchMode && targetTask.inPinnedWindowingMode()));
原因分析
厂商定制导致代码行号不匹配
小米、一加等厂商会基于AOSP的特定版本进行系统框架定制,包括增删代码、调整逻辑顺序等操作,这直接导致设备上运行的ActivityStarter.java行号和谷歌官方仓库的公开版本完全不对应,所以无法在官方代码中找到崩溃栈标注的第2068行逻辑。定制代码缺失空值校验
厂商修改了ActivityStarter.isAllowedToStart()方法的逻辑,新增了直接调用inPinnedWindowingMode()的代码路径,且未对调用该方法的对象做非空判断。而官方代码中,调用inPinnedWindowingMode()的targetTask对象在调用isUidPresent()前已经过空值校验,不会触发NPE——这也是为什么官方代码逻辑和崩溃栈表现不一致的核心原因。场景特殊性导致无法复现
该崩溃仅触发于厂商定制的窗口管理逻辑下的边缘场景(比如特定的固定窗口、分屏切换状态),这类场景的触发条件极为小众,因此仅出现少量用户反馈且难以复现。
内容的提问来源于stack exchange,提问作者David Karlsson
相关产品推荐
相关产品推荐

