一. 问题描述
1.1 现象
手机kernel启动时狂点屏幕会导致手机卡死重启.
1.3 结论
因为surfaceflinger主线程在等中断处理函数执行执行结束,而中断处理函数一直没有执行完,所以导致surfaceflinger的主线程卡住.这时候system_server通过binder跨进程去调用 surfaceflinger中的方法时,由于surfaceflinger卡住了,所以system_server也会被卡住,最终导致了system_server watchdog.
1.4修复链接:
XXX
二. 初步分析
2.1 查看system_server trace
一般对于watchdog问题,我们都会先看看system_server的那一个线程出了问题,出现问题的具体调用栈如下:
从这里我们能看到system_server的binder线程在向surfaceflinger发起跨进程调用时被block了,具体的调用方法是createSurface,那么接下来我们就去看看surfaceflinger的trace,看看它在干什么事情.
2.1 查看surfaceflinger trace
我下了好几份log,都没有发现watchdog文件中有surfaceflinger的trace,没有能继续往下分析,只能先去找没有打印出surfaceflinger trace的原因.
2.2 surfaceflinger打不出trace的怀疑点
①debuggerd出问题了?
不会出问题,要是它出了问题,其他native进程也不会打印出对应的trace.
②watchdog类里把中surfaceflinger这个要抓trace的进程给去掉了?然后查看了下c8对应的代码:
surfaceflinger这个进程还在默认的列表里面,这就比较奇怪了,然后再继续下载了几十份Log,然而没有一份log有surfaceflinger的trace.
继续看下相应的Log,debuggerd确实打印了相应的log
12-29 20:42:17.814 695 831 W SurfaceFlinger: setTransactionState timed out waiting for previous animation frame 12-29 20:42:19.695 2912 3259 W PushService: 2017-12-29 20:42:19,695 - [WARN::PushService] - [Thread:99] [Slim] Wrote {cmd=SECMSG;chid=5;len=341} 12-29 20:42:19.695 2912 3259 W PushService: 2017-12-29 20:42:19,695 - [WARN::PushService] - [Thread:99] [Slim] 08:42:19 ä¸å Sent Blob [SECMSG,5,5QbAV-13] 12-29 20:42:19.695 933 5418 I ExtendedUtils: printFileName fd(15) -> /system/media/audio/notifications/CrystalRing.ogg 12-29 20:42:19.695 2912 3259 W PushService: 2017-12-29 20:42:19,695 - [WARN::PushService] - [Thread:99] try send mi push message. packagename:com.miui.powerkeeper action:Notification 12-29 20:42:19.696 2912 3259 W PushService: 2017-12-29 20:42:19,695 - [WARN::PushService] - [Thread:99] [Slim] Wrote {cmd=SECMSG;chid=5;len=349} 12-29 20:42:22.955 695 831 W SurfaceFlinger: setTransactionState timed out waiting for previous animation frame 12-29 20:43:16.835 591 591 W : debuggerd: handling request: pid=695 uid=1000 gid=1003 tid=695 12-29 20:43:26.849 591 591 W : debuggerd: resuming target 695 12-29 20:43:26.854 591 591 W : debuggerd: handling request: pid=923 uid=1041 gid=1005 tid=923 12-29 20:43:26.857 590 590 W : debuggerd: handling request: pid=923 uid=1041 gid=1005 tid=923 12-29 20:43:26.999 591 591 W : debuggerd: handling request: pid=924 uid=1047 gid=1005 tid=924 12-29 20:43:27.000 590 590 W : debuggerd: handling request: pid=924 uid=1047 gid=1005 tid=924 12-29 20:43:27.106 591 591 W : debuggerd: handling request: pid=925 uid=1019 gid=1019 tid=925 12-29 20:43:27.107 590 590 W : debuggerd: handling request: pid=925 uid=1019 gid=1019 tid=925 12-29 20:43:27.120 591 591 W : debuggerd: handling request: pid=926 uid=0 gid=0 tid=926 12-29 20:43:57.857 5557 5557 W : debuggerd: handling request: pid=695 uid=1000 gid=1003 tid=695 12-29 20:44:07.870 5557 5557 W : debuggerd: resuming target 695 12-29 20:44:07.876 5557 5557 W : debuggerd: handling request: pid=923 uid=1041 gid=1005 tid=923 12-29 20:44:07.878 590 590 W : debuggerd: handling request: pid=923 uid=1041 gid=1005 tid=923 12-29 20:44:07.931 5557 5557 W : debuggerd: handling request: pid=924 uid=1047 gid=1005 tid=924 12-29 20:44:07.932 590 590 W : debuggerd: handling request: pid=924 uid=1047 gid=1005 tid=924 12-29 20:44:08.044 5557 5557 W : debuggerd: handling request: pid=925 uid=1019 gid=1019 tid=925 12-29 20:44:08.045 590 590 W : debuggerd: handling request: pid=925 uid=1019 gid=1019 tid=925 12-29 20:44:08.056 5557 5557 W : debuggerd: handling request: pid=926 uid=0 gid=0 tid=926 |
③surfaceflinger进程中的莫个线程D状态了.
由于没有现场,无法确认.
由于第一,第二种都被排除了,只有第三种最可疑了,如果是第三种情况的话,那就肯定是bsp同事合入的代码有问题导致的.
2.3 排查当时合入的代码
由于没有surfaceflinger的trace,暂时无法继续往下分析了.只能去排查当时进了哪些代码,并且让测试帮忙跑稳定性测试,看看能不能复现.然后排查了一波代码,发现几个改动比较大的,发了邮件让相关的owner自己检查一下,具体的change如下:
邮件也发完了,但是大家好像都比较自信,都相信自己的change没有问题.
2.4 重新查看Log,查找规律
大家都不愿意怀疑自己的change有问题,只能重新回去看看log.看下所有的Log中共同存在的特征.然后终于找到了突破口:
<2>[ 0.883908] Kernel BUG at ffffff94ce9ca228 [verbose debug info unavailable] <0>[ 0.883914] Internal error: Oops - BUG: 96000005 [#1] PREEMPT SMP <2>[ 0.892330] Kernel BUG at ffffff94ce2bc178 [verbose debug info unavailable] <0>[ 0.892335] Internal error: Oops - BUG: 96000005 [#2] PREEMPT SMP <4>[ 0.893028] [] do_mem_abort+0x40/0x9c |
第一个kernel空指针,具体详细log如下:
<1>[ 0.883781] Unable to handle kernel NULL pointer dereference at virtual address 00000200 <1>[ 0.883797] pgd = ffffff94d0e3f000 <1>[ 0.883802] [00000200] *pgd=00000001f65e2003, *pud=00000001f65e2003, *pmd=0000000000000000 <4>[ 0.883903] ------------[ cut here ]------------ <2>[ 0.883908] Kernel BUG at ffffff94ce9ca228 [verbose debug info unavailable] <0>[ 0.883914] Internal error: Oops - BUG: 96000005 [#1] PREEMPT SMP <4>[ 0.883921] Modules linked in: <4>[ 0.883934] CPU: 0 PID: 327 Comm: irq/265-synapti Not tainted 4.4.21-perf-g91f9a92-00622-gee0535c #1 <4>[ 0.883939] Hardware name: Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, Int Codec, jason (DT) <4>[ 0.883946] task: ffffffe1f38bbe80 ti: ffffffe1f37a4000 task.ti: ffffffe1f37a4000 <4>[ 0.883964] PC is at synaptics_rmi4_add_and_update_tp_data+0x24/0x124 <4>[ 0.883975] LR is at input_event+0x20c/0x23c <4>[ 0.883980] pc : [] lr : [] pstate: 80000145 <4>[ 0.883985] sp : ffffffe1f37a7af0 ...... <0>[ 0.884485] Process irq/265-synapti (pid: 327, stack limit = 0xffffffe1f37a4020) <4>[ 0.884491] Call trace: <4>[ 0.884499] Exception stack(0xffffffe1f37a7920 to 0xffffffe1f37a7a50) <4>[ 0.884505] 7920: ffffffe1f30a9800 0000008000000000 ffffffe1f37a7af0 ffffff94ce9ca228 <4>[ 0.884511] 7940: ffffffe1f37a7c30 ffffff94cf9a348d ffffff94cf988f15 0000000000000000 <4>[ 0.884517] 7960: ffffffe09522d600 0000000000000000 ffffffe1f48cc54c 0000000000000002 <4>[ 0.884524] 7980: ffffffe1f37a79b0 ffffff94ce58676c 0000000000000000 ffffffe09522d800 <4>[ 0.884530] 79a0: ffffffe09522de80 ffffff94cf289758 ffffffe1f37a79f0 ffffff94ce9f567c <4>[ 0.884536] 79c0: 0000000000000000 0000000000000002 0000000000000007 0000000000000000 <4>[ 0.884542] 79e0: ffffffe1f30aa000 0000000000000001 000000000000009e ffffffe1f6075098 <4>[ 0.884549] 7a00: ffffffe1f37a7c20 ffffffe1f37a4000 00000000000008c0 0000000034ac5486 <4>[ 0.884555] 7a20: 0000000000989680 00000000001b69db 00000000004629df 00000000273b6cc9 <4>[ 0.884561] 7a40: 000000005a858216 0000000019d08b13 <4>[ 0.884569] [] synaptics_rmi4_add_and_update_tp_data+0x24/0x124 <4>[ 0.884577] [] input_event+0x20c/0x23c <4>[ 0.884587] [] synaptics_rmi4_sensor_report+0xa50/0x1008 <4>[ 0.884593] [] synaptics_rmi4_irq+0x40/0x50 <4>[ 0.884604] [] irq_thread_fn+0x28/0x68 <4>[ 0.884610] [] irq_thread+0xfc/0x1c4 <4>[ 0.884622] [] kthread+0xdc/0xe4 <4>[ 0.884631] [] ret_from_fork+0x10/0x20 <0>[ 0.884639] Code: f944a680 f90057a0 d0011a60 f947a800 (f9410000) <4>[ 0.884677] ---[ end trace e92029382e65dac3 ]--- |
这个log大概就是说irq/265-synapti进程在kernel里发生了一个空指针,空指针的位置在synaptics_rmi4_add_and_update_tp_data方法中
第二个kernel空指针,具体详细log如下:
<1>[ 0.892273] Unable to handle kernel paging request at virtual address ffffffffffffffd8 <1>[ 0.892278] pgd = ffffff94d0e3f000 <1>[ 0.892283] [ffffffffffffffd8] *pgd=0000000000000000, *pud=0000000000000000 <4>[ 0.892324] ------------[ cut here ]------------ <2>[ 0.892330] Kernel BUG at ffffff94ce2bc178 [verbose debug info unavailable] <0>[ 0.892335] Internal error: Oops - BUG: 96000005 [#2] PREEMPT SMP <4>[ 0.892339] Modules linked in: <4>[ 0.892349] CPU: 0 PID: 327 Comm: irq/265-synapti Tainted: G D 4.4.21-perf-g91f9a92-00622-gee0535c #1 <4>[ 0.892354] Hardware name: Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, Int Codec, jason (DT) <4>[ 0.892359] task: ffffffe1f38bbe80 ti: ffffffe1f37a4000 task.ti: ffffffe1f37a4000 <4>[ 0.892366] PC is at kthread_data+0x4/0xc <4>[ 0.892373] LR is at irq_thread_dtor+0x44/0xb8 <4>[ 0.892378] pc : [] lr : [] pstate: 60000145 <4>[ 0.892383] sp : ffffffe1f37a7720 ...... <0>[ 0.892886] Process irq/265-synapti (pid: 327, stack limit = 0xffffffe1f37a4020) <4>[ 0.892890] Call trace: <4>[ 0.892896] Exception stack(0xffffffe1f37a7550 to 0xffffffe1f37a7680) <4>[ 0.892901] 7540: ffffffe1f38bbe80 0000008000000000 <4>[ 0.892908] 7560: ffffffe1f37a7720 ffffff94ce2bc178 ffffffbe47d25480 000000000001d518 <4>[ 0.892915] 7580: ffffffe1f37a4000 ffffff94ce2e1c80 ffffffe1f37a76b0 ffffff94ce3a46e0 <4>[ 0.892923] 75a0: ffffffbe47d25480 ffffffe1f4952a80 ffffffe1f37a4000 ffffffe1f6403e00 <4>[ 0.892931] 75c0: ffffffe1f37a4000 000000000001d518 ffffff94d08c9000 00000000000000ff <4>[ 0.892937] 75e0: 0000000000000005 ffffffe1f37a4000 0000000000000000 ffffff94ce2f7464 <4>[ 0.892944] 7600: 0000000000000000 0000000000000000 ffffffe1f38bc598 0000000003acb1da <4>[ 0.892950] 7620: 0000000000000004 0000000000000000 ffffffe1f4952aa0 ffffffe1f7562c88 <4>[ 0.892958] 7640: ffffffe1f7562c78 00000000352e65d8 0000000000989680 000000000019b13d <4>[ 0.892965] 7660: 7265626d756e202c ffffff94cf2c0000 0000000000000007 000000000000000e <4>[ 0.892972] [] kthread_data+0x4/0xc <4>[ 0.892980] [] task_work_run+0x98/0xb8 <4>[ 0.892989] [] do_exit+0x3e4/0x850 <4>[ 0.892998] [] die+0x23c/0x254 <4>[ 0.893008] [] __do_kernel_fault.part.5+0x74/0x90 <4>[ 0.893015] [] do_page_fault+0x2ac/0x30c <4>[ 0.893021] [] do_translation_fault+0x44/0xc0 <4>[ 0.893028] [] do_mem_abort+0x40/0x9c <4>[ 0.893033] Exception stack(0xffffffe1f37a7920 to 0xffffffe1f37a7a50) <4>[ 0.893039] 7920: ffffffe1f30a9800 0000008000000000 ffffffe1f37a7af0 ffffff94ce9ca228 <4>[ 0.893047] 7940: ffffffe1f37a7c30 ffffff94cf9a348d ffffff94cf988f15 0000000000000000 <4>[ 0.893052] 7960: ffffffe09522d600 0000000000000000 ffffffe1f48cc54c 0000000000000002 <4>[ 0.893059] 7980: ffffffe1f37a79b0 ffffff94ce58676c 0000000000000000 ffffffe09522d800 <4>[ 0.893066] 79a0: ffffffe09522de80 ffffff94cf289758 ffffffe1f37a79f0 ffffff94ce9f567c <4>[ 0.893073] 79c0: 0000000000000000 0000000000000002 0000000000000007 0000000000000000 <4>[ 0.893079] 79e0: ffffffe1f30aa000 0000000000000001 000000000000009e ffffffe1f6075098 <4>[ 0.893086] 7a00: ffffffe1f37a7c20 ffffffe1f37a4000 00000000000008c0 0000000034ac5486 <4>[ 0.893094] 7a20: 0000000000989680 00000000001b69db 00000000004629df 00000000273b6cc9 <4>[ 0.893099] 7a40: 000000005a858216 0000000019d08b13 <4>[ 0.893107] [] el1_da+0x18/0x78 <4>[ 0.893114] [] input_event+0x20c/0x23c <4>[ 0.893122] [] synaptics_rmi4_sensor_report+0xa50/0x1008 <4>[ 0.893129] [] synaptics_rmi4_irq+0x40/0x50 <4>[ 0.893137] [] irq_thread_fn+0x28/0x68 <4>[ 0.893144] [] irq_thread+0xfc/0x1c4 <4>[ 0.893151] [] kthread+0xdc/0xe4 <4>[ 0.893159] [] ret_from_fork+0x10/0x20 <0>[ 0.893166] Code: a9425bf5 a8c97bfd d65f03c0 f942dc00 (f85d8000) <4>[ 0.893172] ---[ end trace e92029382e65dac4 ]--- <1>[ 0.901675] Fixing recursive fault but reboot is needed! |
这个log和第一个很类似就是irq/265-synapti进程在kernel里发生了一个空指针,空指针的位置在kthread_data方法中.
还有一个比较关键的一个地方是:
Fixing recursive fault but reboot is needed!
这里说我们遇到了一个递归的故障,需要reboot才能解决,具体代码如下:
从我们的Log中也能看到这是一个连续发生的空指针问题,先发生了一次空指针,然后调用do_exit,在后续的流程中又发生了空指针,然后就陷入了一个循环挂掉的流程中,然后就调用到了schedule()方法,最终陷入D状态.
三. 深入分析
初步分析后我们发现每次发生这个watchdog问题都有一个kernel 空指针问题发生,然后顺着这个空指针我们能找到当时合入的一个change:XXX
空指针的地方就是这个change里加入的,然后和钟桂林沟通了一下,有了这个复现路径。
因为我们抓到的所有trace文件中并没有surafaceflinger的trace,这个很有可能是由于surafaceflinger进程中的某个线程D状态了导致的.所以复现之后直接ps -t | grep " D "查看一下存在的D状态的线程,我们可以看到如下线程:
root 327 2 0 0 do_exit 0000000000 D irq/265-synapti system 692 1 192972 40920 synchroniz 7fb6732320 D /system/bin/surfaceflinger |
surfaceflinger和irq/265-synapti进程都D状态了
3.1 分析irq/265-synapti进程
抓了一个kernel的ramdump,打印了一下当前的调用栈:
从这个调用栈中我们能看出有个中断处理函数在synaptics_rmi4_add_and_update_tp_data方法中发生了一次空指针,然后线程要退出,但是在执行到task_work_run方法中时又发生了空指针,然后调用到schedule方法.最终导致了这个线程D状态.(当手指触摸屏幕的时候会在硬件上产生一个中断,然后调用在probe函数中配置好的中断处理函数)
第一个空指针的具体推到如下:
我们从调用栈中能看到空指针的位置是在synaptics_rmi4_add_and_update_tp_data+36,然后我们可以看一下这个方法当时的汇编信息:
我们直接找到+36的位置:
我们从+28/+32/+36这几行大概能看出来如下内容:+28这行先将0xffffff8a9f318000地址的内容放到x0寄存器中,+32这行将x0寄存器偏移到相对x0的#3920,+36这行又将x0再偏移到相对x0的#512位置。
我们大概能知道这里是再取地址,然后再对比下源码:
结合汇编代码我们对再比代码后就能看出来,这里是在8208行出现问题了,出现问题的原因是:f54->rmi4_data是空指针。
f54是个全局变量对应:adrp x0, 0xffffff8a9f318000
然后我们要去取f54->rmi4_data的地址,对应:ldr x0, [x0,#3920]
接着我们去取f54->rmi4_data->es_enabled,对应:ldr x0, [x0,#512]
但是f54->rmi4_data是个空指针,所以在“ldr x0, [x0,#512]”时就会报错了,接着这个中断处理函数就挂了,接着就开始退出了。
第二个空指针的具体推到如下:
我们前边说了中断处理函数出现空指针然后开始退出,但是退出的时候又空指针了,我们直接去看的汇编信息:
直接对比下源代码:
这里也是在取地址的时候空指针的,这个空指针的具体原因就不深究了,很可能就是因为上一个task执行出错导致了,这里出现空指针,有兴趣的同学可以研究一下。
那么程序退出为什么会进入D状态呢?我们取看开exit.c中的代码:
就是线程在退出的时候陷入了一个循环,就会调用到schedule,最终该线程会进入到D状态
3.2 分析surfaceflinger进程
好了irq/265-synapti进程中的主线程D状态的大概原因说完了,我们再看看surfaceflinger进程当时再干嘛:
jason:/ # ps -t 692 USER PID PPID VSIZE RSS WCHAN PC NAME system 692 1 192972 40920 synchroniz 7fb6732320 D /system/bin/surfaceflinger system 757 692 192972 40920 binder_thr 7fb6732320 S Binder:692_1 system 759 692 192972 40920 futex_wait 7fb66d5ef0 S DispSync system 760 692 192972 40920 binder_thr 7fb6732320 S Binder:692_2 system 838 692 192972 40920 do_sigtime 7fb6732410 S POSIX timer 0 system 839 692 192972 40920 futex_wait 7fb66d5ef0 S EventThread system 840 692 192972 40920 poll_sched 7fb6732350 S HWC_UeventThrea system 846 692 192972 40920 poll_sched 7fb6732350 S SDM_EventThread system 848 692 192972 40920 futex_wait 7fb66d5ef0 S EventControl system 868 692 192972 40920 futex_wait 7fb66d5ef0 S Binder:692_3 system 2472 692 192972 40920 binder_thr 7fb6732320 S Binder:692_4 system 3558 692 192972 40920 binder_thr 7fb6732320 S Binder:692_5 |
我们发现surfaceflinger的主线程D状态了,然后我们接着看下692这个进程的kernel的调用栈:
我们这里直接找到对应的源码:
看到这里可能会有人有疑问了,调用栈里synchronize_irq里不是调用了schedule方法吗?这里没有看到这个方法呀,弄错了?开始我也怀疑我找错了,然后我们看下wati_event的定义,
我们能看到这里用的都是define来定义的,所以wat_event并不是一个具体的函数方法:
在__wait_event中我们传入了一个schedule方法,
最后会执行schedule方法。
我们再仔细看看synchronize_irq方法的注释:
/** * synchronize_irq - wait for pending IRQ handlers (on other CPUs)
* @irq: interrupt number to wait for This function waits for any pending IRQ handlers for this interrupt
* to complete before returning. If you use this function while holding a resource the IRQ handler may need you will deadlock.
* This function may be called - with care - from IRQ context. */
大概意思是说:
synchronize_irq 方法在返回前需要等待任意一个 IRQ处理函程序数执行完成。当你持有中断处理程序时,如果你使用这个函数,就可能造成死锁。
那我们看看这里再等待哪一个irq呢?我们看到disable_irq方法中来,disable_irq方法的参数就是对应的irq,那么我们就从ramdump中来看开这个irq的值是多少,首先我们能看到如下方法:
disable_irq的第一个参数就是irq,那么我们就去找找这个参数的值是多少:
我们先看看这个方法的汇编信息,因为这个方法只有一个参数,他的irq就是存在w0寄存器中的,这个方法中我们并不能找到w0的地址我们继续往上一级函数synaptics_rmi4_irq_enable看看:
我们从disable_irq和synaptics_rmi4_irq_enable汇编信息来做如下推断:
1.disable_irq的irq保存再w0寄存器中,所以synaptics_rmi4_irq_enable方法在调用disable_irq方法时会将irq的值保存在w0中然后调用disable_irq方法,我们能看到disable_irq方法的地址是0xffffff8a9c8f7990,所以在synaptics_rmi4_irq_enable的栈中我们能找到这个地址,就是图上白色的地方,我们能看到w0是,x0偏移了#808得到的,我们再结合代码:
所以我们能推断出x0存的肯定是rmi4_data的地址。因为后边还会用到rmi4_data,而x0这个寄存器会在调用方法时被修改(传参),所以rmi4_data肯定会存在其他的寄存器上保存,我们在找找synaptics_rmi4_irq_enable栈上的信息,看看x0会把地址保存在哪一个寄存器上,我们能发现,他保存在了x19上,并且这个栈中没有再修改x19,那么我们再看到disable_irq栈上来:
x19是sp偏移16得到的,那么我们继续找到sp的地址:
所以x19的地址是:0xffffffce2f173a50+16
那么我们打印一下rmi4_data存的所有数据的值,里边肯定存在irq的值:
。。。
。。。
我们能找到对应的irq号,它为256.
当然了irq/265-synapti进程的调用栈也用类似的方法我们也能找到它的中断号,也为:265。这里就不反复推到浪费大家时间了。
三. 拨开云雾见青天
我们再来回顾一下,首先是irq/265-synapti进程执行中断处理函数时发生了空指针异常自己连续挂了两次,并进入D状态卡住,然后surfaceflinger在等待它的中断处理函数执行结束,由于执行中断处理函数的进程已经进入D状态,因此中断处理函数永远无法执行结束,最终导致surfaceflinger也卡住了,这时候system_server通过同步binder 调用到surfaceflinger,因为surfaceflinger无法处理,所以system_server也会卡住,最终导致了system_server watchdog.所以这个问题只需要将最开始的空指针问题修复,那么就能修复这个问题了:XXX
四. 其他疑问
1.kernel空指针为什么没有重启?
没有重启的原因是没有走panic的流程,原因如下:
http://guard.pt.miui.com/opengrok2/xref/v8-n-jason-dev/kernel/msm-4.4/arch/arm64/kernel/traps.c#313
http://guard.pt.miui.com/opengrok2/xref/v8-n-jason-dev/kernel/msm-4.4/kernel/panic.c#34
触发panic有一个标志:panic_on_oops,它的值在c8上默认是0
311 if (in_interrupt())
312 panic("Fatal exception in interrupt");
313 if (panic_on_oops)
314 panic("Fatal exception");
315 if (notify != NOTIFY_STOP)
316 do_exit(SIGSEGV);
317}
panic_on_oops标志设置为1是在init进程中:
http://guard.pt.miui.com/opengrok2/xref/v8-n-jason-dev/system/core/rootdir/init.rc#114
发生这个空指针的时候init进程还没有起来