今天遇到一个 monkey 测试中发现的 sendOrderedBroadcast fail 的问题。记录一下。
错误 log 如下:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
Shutting down VM
 07-04 06:11:24.319 W/dalvikvm(23361): threadid=1: thread exiting with uncaught exception (group=0x415a8898)
 07-04 06:11:24.319 W/BroadcastQueue(  937): Failure sending broadcast Intent { act=android.intent.action.QUERY_PACKAGE_RESTART dat=package:com.cootek.smartinputv5.language.cangjie flg=0x10 (has extras) }
 07-04 06:11:24.319 W/BroadcastQueue(  937): android.os.DeadObjectException
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at android.os.BinderProxy.transact(Native Method)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at android.content.IIntentReceiver$Stub$Proxy.performReceive(IIntentReceiver.java:124)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at com.android.server.am.BroadcastQueue.performReceiveLocked(BroadcastQueue.java:376)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at com.android.server.am.BroadcastQueue.deliverToRegisteredReceiverLocked(BroadcastQueue.java:449)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at com.android.server.am.BroadcastQueue.processNextBroadcast(BroadcastQueue.java:656)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at com.android.server.am.ActivityManagerService.finishReceiver(ActivityManagerService.java:12451)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at android.content.BroadcastReceiver$PendingResult.sendFinished(BroadcastReceiver.java:419)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at android.content.BroadcastReceiver$PendingResult.finish(BroadcastReceiver.java:395)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:780)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at android.os.Handler.handleCallback(Handler.java:730)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at android.os.Handler.dispatchMessage(Handler.java:92)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at android.os.Looper.loop(Looper.java:137)
 07-04 06:11:24.319 W/BroadcastQueue(  937):   at com.android.server.ServerThread.run(SystemServer.java:1066)
 
 07-04 06:11:24.329 E/AndroidRuntime(23361): FATAL EXCEPTION: main
 07-04 06:11:24.329 E/AndroidRuntime(23361): java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.QUERY_PACKAGE_RESTART dat=package:com.cootek.smartinputv5.language.cangjie flg=0x10 (has extras) } in com.android.settings.applications.InstalledAppDetails$2@42070e38
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:773)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at android.os.Handler.handleCallback(Handler.java:730)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at android.os.Handler.dispatchMessage(Handler.java:92)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at android.os.Looper.loop(Looper.java:137)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at android.app.ActivityThread.main(ActivityThread.java:5136)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at java.lang.reflect.Method.invokeNative(Native Method)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at java.lang.reflect.Method.invoke(Method.java:525)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at dalvik.system.NativeStart.main(Native Method)
 07-04 06:11:24.329 E/AndroidRuntime(23361): Caused by: java.lang.NullPointerException
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at com.android.settings.applications.InstalledAppDetails$2.onReceive(InstalledAppDetails.java:1225)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:763)
 07-04 06:11:24.329 E/AndroidRuntime(23361):   ... 9 more
 07-04 06:11:24.329 I/ActivityManager(  937): Notify an ApplicationCrash 
查看下代码:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
1218      private  final  BroadcastReceiver  mCheckKillProcessesReceiver  =  new  BroadcastReceiver ()  { 
1219          @Override 
1220          public  void  onReceive ( Context  context ,  Intent  intent )  { 
1221              updateForceStopButton ( getResultCode ()  !=  Activity . RESULT_CANCELED ); 
1222 
1223              Intent  i  =  new  Intent ( "qualcomm.android.LEDFlashlight.processKilled" ); 
1224              i . putExtra ( Intent . EXTRA_PACKAGES ,  mAppEntry . info . packageName ); 
1225              getActivity (). sendStickyBroadcast ( i ); 
1226          } 
1227      }; 
可以看出 NullPointerException 的直接原因是 getActivity 失败了~
1 
1225              getActivity (). sendStickyBroadcast ( i ); 
可是这个怎么会失败呢?
Stack Overflow  上搜索到的 解释  :
I can see this happening if the component that called sendOrderedBroadcast() was destroyed prior to the broadcast winding its way back to the supplied instance of the BroadcastReceiver anonymous subclass.
这个解释说是因为 sendOrderedBroadcast() 的组件在 broadcast 还没有回调到这个匿名内部类的实例 mCheckKillProcessesReceiver  的时候就已经 destroy 了。
虽然我没有亲自验证,但是有两个问题:
如果 component 已经 destroy 了,按照 Android 的机制,那么 intent 过来的时候应该重新构造这个 component 才对,那么 destroy 又有什么关系呢? 
这个匿名内部类的实例化是怎么完成的? 实例化的时候是否正确的创建了 Context 信息?