回复itatoo

####################################10.22#################################################################

一些新的疑问及思路:

1.我在你的Log里发现

回复itatoo_第1张图片

 

我的源码里找不到这个文件,也没报这个错误。还有你看607,sensors.oem.so 建议你排查一下,看你那个问题就是 chanel被关闭了,不清楚会不会因为这些库啥的出问题导致一些chanel 被关闭。

回复itatoo_第2张图片

 

2.关于bug位置,

对,你说的没错,messagechannel.cpp那里只是获得的一个结果,died掉的那几个服务也只是结果,原因在于你的Compositor线程获取了一个错误地址。直接原因是,某chanel被关闭了。谁被关闭了,为什么关闭?https://my.oschina.net/ibuwai/blog/653345

回复itatoo_第3张图片

 

回复itatoo_第4张图片

 

 

 

3.一个可能最省力的办法,换2.5的源码。我用的2.5的。关于源码的版本,2.6是最新的,似乎有很多bug.没修复项目就die了。所以建议使用2.5的源码。

 

PS:有进展欢迎跟我分享,我也学习一下。

 

最近在分析ing APP启动过程,技术菜,但还没搞清,你可以随便看看是否有点启发。

https://blog.csdn.net/hunter___/article/details/82910601

 

 

附我的正常系统Log,

我自己的无关log你自己忽略。

--------- beginning of /dev/log/system
I/Vold    (  166): Vold 2.1 (the revenge) firing up
--------- beginning of /dev/log/main
I/GeckoConsole(  178): Could not read chrome manifest 'file:///system/b2g/chrome.manifest'.
D/MDnsDS  (  169): MDnsSdListener::Hander starting up
D/MDnsDS  (  169): MDnsSdListener starting to monitor
D/MDnsDS  (  169): Going to poll with pollCount 1
I/kickstart-qcks(  168): EFS Prepend
I/kickstart-qcks(  168): File:'/firmware/image/efs1.mbn' is available for reading
I/kickstart-qcks(  168): File:'/firmware/image/efs2.mbn' is available for reading
I/kickstart-qcks(  168): File:'/dev/block/platform/msm_sdcc.1/by-name/m9kefs1' is available for reading
I/kickstart-qcks(  168): File:'/dev/block/platform/msm_sdcc.1/by-name/m9kefs2' is available for reading
I/kickstart-qcks(  168): File:'/firmware/image/acdb.mbn' is available for reading
I/kickstart-qcks(  168): File:'/firmware/image/mdm_acdb.img' is available for reading
I/kickstart-qcks(  168): Reading RAW EFS1 partition
I/kickstart-qcks(  168): Running dd if=/dev/block/platform/msm_sdcc.1/by-name/m9kefs1 of=/data/qcks/temp.dump bs=1024 count=3072
I/kickstart-qcks(  168): Combining Header1 with RAW EFS1 partition
I/kickstart-qcks(  168): Running cat /firmware/image/efs1.mbn /data/qcks/temp.dump > /data/qcks/efs1.bin
I/kickstart-qcks(  168): Reading RAW EFS2 partition
I/kickstart-qcks(  168): Running dd if=/dev/block/platform/msm_sdcc.1/by-name/m9kefs2 of=/data/qcks/temp.dump bs=1024 count=3072
I/kickstart-qcks(  168): Combining Header2 with RAW EFS2 partition
I/kickstart-qcks(  168): Running cat /firmware/image/efs2.mbn /data/qcks/temp.dump > /data/qcks/efs2.bin
I/kickstart-qcks(  168): Reading RAW EFS3 partition
I/kickstart-qcks(  168): Running dd if=/dev/block/platform/msm_sdcc.1/by-name/m9kefs3 of=/data/qcks/temp.dump bs=1024 count=3072
I/kickstart-qcks(  168): Combining Header3 with RAW EFS3 partition
I/kickstart-qcks(  168): Running cat /firmware/image/efs3.mbn /data/qcks/temp.dump > /data/qcks/efs3.bin
I/kickstart-qcks(  168): Combining ACDB Header with ACDB binary
I/kickstart-qcks(  168): Running cat /firmware/image/acdb.mbn /firmware/image/mdm_acdb.img > /data/qcks/acdb.bin
I/kickstart-qcks(  168): Loading Sahara images
I/kickstart-qcks(  168): Testing if port "/dev/ks_hsic_bridge" exists
E/kickstart-qcks(  168): RUNNING:	/system/bin/ks  -w /data/tombstones/mdm/ -p /dev/ks_hsic_bridge -r 21 -s 2:/firmware/image/amss.mbn -s 6:/firmware/image/apps.mbn -s 8:/firmware/image/dsp1.mbn -s 11:/firmware/image/osbl.mbn -s 12:/firmware/image/dsp2.mbn -s 21:/firmware/image/sbl1.mbn -s 22:/firmware/image/sbl2.mbn -s 23:/firmware/image/rpm.mbn -s 28:/firmware/image/dsp3.mbn -s 16:/data/qcks/efs1.bin -s 17:/data/qcks/efs2.bin -s 20:/data/qcks/efs3.bin -s 29:/data/qcks/acdb.bin
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 21, file "/firmware/image/sbl1.mbn"
E/kickstart(  600): 117700 bytes transferred in 0.132s (0.85 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 23, file "/firmware/image/rpm.mbn"
E/kickstart(  600): 105696 bytes transferred in 0.020s (5.09 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 22, file "/firmware/image/sbl2.mbn"
E/kickstart(  600): 242376 bytes transferred in 0.032s (7.28 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 12, file "/firmware/image/dsp2.mbn"
E/ServiceManager(  165): add_service('android.security.keystore',0xc) uid=0 - ALREADY REGISTERED, OVERRIDE
I/ServiceManager(  165): service 'android.security.keystore' died
I/VolumeManager(  178): changing state from 'Uninitialized' to 'Starting'
I/VolumeManager(  178): Connected to vold
I/VolumeManager(  178): Volume sdcard (1): changing state from Init to Mounted @ '/mnt/shell/emulated/0' (1 observers) mountGeneration = 1, locked = 0
I/VolumeManager(  178): READY: Volume: sdcard (1) is Mounted and inserted @ /mnt/shell/emulated/0 gen 1 locked 0
I/VolumeManager(  178): READY:   Sharing x Mounting n Formating n Unmounting n
I/VolumeManager(  178): changing state from 'Starting' to 'Volumes Ready'
I/AutoMounter(  178): UpdateState: ums:A0C0E0 mtp:A1C0E0 mode:0 usb:1 tryToShare:0 state:IDLE
I/AutoMounter(  178): UpdateState: Volume sdcard is Mounted and inserted @ /mnt/shell/emulated/0 gen 1 locked 0 sharing x
I/ServiceManager(  178): Waiting for service media.audio_policy...
I/ServiceManager(  178): Waiting for service media.audio_policy...
I/ServiceManager(  178): Waiting for service media.audio_policy...
I/ServiceManager(  178): Waiting for service media.audio_policy...
E/kickstart(  600): 32137174 bytes transferred in 3.412s (8.98 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 28, file "/firmware/image/dsp3.mbn"
I/ServiceManager(  178): Waiting for service media.audio_policy...
E/kickstart(  600): 6334186 bytes transferred in 0.655s (9.22 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 8, file "/firmware/image/dsp1.mbn"
E/kickstart(  600): 2688527 bytes transferred in 0.320s (8.02 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 16, file "/data/qcks/efs1.bin"
E/kickstart(  600): 786472 bytes transferred in 0.076s (9.83 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 17, file "/data/qcks/efs2.bin"
E/kickstart(  600): 786472 bytes transferred in 0.076s (9.81 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 20, file "/data/qcks/efs3.bin"
E/kickstart(  600): 786472 bytes transferred in 0.070s (10.65 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 29, file "/data/qcks/acdb.bin"
E/kickstart(  600): 2097192 bytes transferred in 0.184s (10.89 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Wrote to /sys/power/wake_lock
E/kickstart(  600): Requested ID 6, file "/firmware/image/apps.mbn"
W/AudioSystem(  178): AudioPolicyService not published, waiting...
E/kickstart(  600): 2630368 bytes transferred in 0.306s (8.21 MBps)
E/kickstart(  600): Wrote to /sys/power/wake_unlock
E/kickstart(  600): Sahara protocol completed
E/kickstart(  600): Removing linked list of input files
E/kickstart(  600): Removing linked list of input files
I/kickstart-qcks(  168): RetCode = 0
E/kickstart-qcks(  168): Sahara transfer completed successfully
E/kickstart-qcks(  168): Spawning efsks
I/kickstart-efsks(  619): EFS_TTY='/dev/efs_hsic_bridge'
I/kickstart-efsks(  619): Parsing 'where to save memorydump' options
I/kickstart-efsks(  619): PathToSaveFiles='/dev/block/platform/msm_sdcc.1/by-name/'
I/kickstart-efsks(  619): EFSKS parameters
I/kickstart-efsks(  619): EFS_TTY='/dev/efs_hsic_bridge'
I/kickstart-efsks(  619): ks_path='/system/bin/ks'
I/kickstart-efsks(  619): PathToSaveFiles='/dev/block/platform/msm_sdcc.1/by-name/'
I/kickstart-efsks(  619): RX_Timeout=-1
E/kickstart-efsks(  619): File '/dev/efs_hsic_bridge' was not found
E/kickstart-efsks(  619): /dev/efs_hsic_bridge does not exist.
I/ServiceManager(  178): Waiting for service media.audio_policy...
I/ServiceManager(  178): Waiting for service media.audio_policy...
E/kickstart-efsks(  619): RUNNING: '/system/bin/ks -m -w /dev/block/platform/msm_sdcc.1/by-name/ -p /dev/efs_hsic_bridge -t -1 -l'
E/kickstart(  622): Wrote to /sys/power/wake_lock
E/kickstart(  622): Wrote to /sys/power/wake_unlock
I/ServiceManager(  178): Waiting for service media.audio_policy...
I/ServiceManager(  178): Waiting for service media.audio_policy...
E/QMI_FW  (  184): QMUXD: Service_id=24 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=24 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=23 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=24 not found over conn_id=0
D/ThermalDaemon(  184): qmi: Instance id 25 for fusion TMD
E/QMI_FW  (  184): QMUXD: Service_id=24 not found over conn_id=0
D/ThermalDaemon(  184): qmi: Instance id 25 for fusion TS
E/QMI_FW  (  184): QMUXD: Service_id=23 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=24 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=24 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=23 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=24 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=23 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=24 not found over conn_id=0
E/QMI_FW  (  184): QMUXD: Service_id=23 not found over conn_id=0
D/ThermalDaemon(  184): Fusion modem thermal mitigation available.
D/ThermalDaemon(  184): Modem thermal sensor service available.
E/QMI_FW  (  173): QMUXD: Service_id=20 not found over conn_id=0
E/QMI_FW  (  173): QMUXD: Service_id=20 not found over conn_id=0
E/QMI_FW  (  173): QMUXD: Service_id=20 not found over conn_id=0
E/QMI_FW  (  173): QMUXD: Service_id=20 not found over conn_id=0
E/QMI_FW  (  173): QMUXD: Service_id=20 not found over conn_id=0
I/AudioFlinger(  173): loadHwModule() Loaded primary audio interface from QCOM Audio HAL (audio) handle 1
I/AudioFlinger(  173): HAL output buffer size 240 frames, normal mix buffer size 960 frames
I/AudioMixer(  173): found effect "Multichannel Downmix To Stereo" from The Android Open Source Project
E/MonoPipe(  173): Failed to fetch local time frequency when constructing a MonoPipe (res = -32).  getNextWriteTimestamp calls will be non-functional
I/AudioFlinger(  173): Using module 1 has the primary audio interface
I/AudioFlinger(  173): AudioFlinger's thread 0xb5d73008 ready to run
W/AudioFlinger(  173): Thread AudioOut_2 cannot connect to the power manager service
D/audio_hw_primary(  173): out_set_parameters: enter: usecase(1: low-latency-playback) kvpairs: routing=2
W/AudioFlinger(  173): Thread AudioOut_2 cannot connect to the power manager service
W/AudioFlinger(  173): Thread AudioOut_2 cannot connect to the power manager service
E/AudioFlinger(  173): no wake lock to update!
I/AudioFlinger(  173): HAL output buffer size 960 frames, normal mix buffer size 960 frames
I/AudioMixer(  173): found effect "Multichannel Downmix To Stereo" from The Android Open Source Project
I/AudioFlinger(  173): AudioFlinger's thread 0xb5b07008 ready to run
W/AudioFlinger(  173): Thread AudioOut_3 cannot connect to the power manager service
D/audio_hw_primary(  173): out_set_parameters: enter: usecase(0: deep-buffer-playback) kvpairs: routing=2
W/AudioFlinger(  173): Thread AudioOut_3 cannot connect to the power manager service
W/AudioFlinger(  173): Thread AudioOut_3 cannot connect to the power manager service
E/AudioFlinger(  173): no wake lock to update!
I/audio_a2dp_hw(  173): adev_open:  adev_open in A2dp_hw module
I/AudioFlinger(  173): loadHwModule() Loaded a2dp audio interface from A2DP Audio HW HAL (audio) handle 4
I/AudioFlinger(  173): loadHwModule() Loaded usb audio interface from USB audio HW HAL (audio) handle 5
I/r_submix(  173): adev_open(name=audio_hw_if)
I/r_submix(  173): adev_init_check()
I/AudioFlinger(  173): loadHwModule() Loaded r_submix audio interface from Wifi Display audio HAL (audio) handle 6
I/AudioPolicyService(  173): Loaded audio policy from LEGACY Audio Policy HAL (audio_policy)
I/Gecko   (  178): MobileConnectionService: init complete
I/Gecko   (  178): 1540169910055	Marionette	INFO	Marionette enabled via build flag and pref
I/Gecko   (  178): yahaha,dump,im SimpleComponentImpl in simplecomponent.js######################### before prototype
I/Gecko   (  178): yahaha SimpleComponent.js ooooooooooooooooooooooooooooooooooooooooo
I/GeckoConsole(  178): While creating services from category 'profile-after-change', service for entry 'simplecomponent', contract ID '@mozilla.org/simplejs;1' does not implement nsIObserver.
I/Gecko   (  178): yahaha,========>start: javascript component==================>
I/Gecko   (  178): yahaha,...result: yourName = Anonymous!
I/Gecko   (  178): Hello yahaha,change after yourName
I/Gecko   (  178): yahaha,========>end: javascript component====================>
I/Gecko   (  178):  
I/Gecko   (  178): yahaha,==========>start test1....instance of other cpp component in usecomponent.js 
I/Gecko   (  178): yahaha,nfc,,,,,,[xpconnect wrapped nsINfcService]
I/Gecko   (  178): yahaha,=========>end test1 ===================================>
I/Gecko   (  178):  
I/Gecko   (  178): yahahacpp,==========>start,test of cpp component==================>
I/        (  178): yohoho,yahahacpp,log from gecko dom simplecpp.cpp component,nsSimplecpp()
I/Gecko   (  178): yahahacpp,before change()
I/        (  178): yohoho,yahahacpp,log from gecko dom simplecpp.cpp,Change()
I/Gecko   (  178): Hello anonymous====>
I/        (  178): yahaha,log from simplecpp.cpp after Changechange()
I/Gecko   (  178): yahahacpp,============>end of cpp component test====================>
I/Gecko   (  178):  
I/        (  178): yohoho,yahahacpp,log from simplecpp.cpp component,Usecomponent()
I/Gecko   (  178): Hello anonymous====>
I/        (  178): yahaha,log from simplecpp.cpp Usecomponent()
I/Gecko   (  178): yahahacpp,after Simplecpp.usecomponent() result of usecomponent:undefined
I/Gecko   (  178): yahaha,this is a null component in useComponentImpl
I/GeckoConsole(  178): While creating services from category 'profile-after-change', service for entry 'usecomponent', contract ID '@mozilla.org/usecomponent;1' does not implement nsIObserver.
I/Gecko   (  178): 1540169910847	Marionette	INFO	Listening on port 2828
D/EventHub(  178): No input device configuration file found for device 'pmic8xxx_pwrkey'.
W/EventHub(  178): Unable to disable kernel key repeat for /dev/input/event0: Function not implemented
I/EventHub(  178): New device: id=1, fd=65, path='/dev/input/event0', name='pmic8xxx_pwrkey', classes=0x1, configuration='', keyLayout='/system/usr/keylayout/pmic8xxx_pwrkey.kl', keyCharacterMap='/system/usr/keychars/pmic8xxx_pwrkey.kcm', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true
D/EventHub(  178): No input device configuration file found for device 'keypad_8064'.
W/EventHub(  178): Unable to disable kernel key repeat for /dev/input/event1: Function not implemented
I/EventHub(  178): New device: id=2, fd=63, path='/dev/input/event1', name='keypad_8064', classes=0x1, configuration='', keyLayout='/system/usr/keylayout/keypad_8064.kl', keyCharacterMap='/system/usr/keychars/keypad_8064.kcm', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true
D/EventHub(  178): No input device configuration file found for device 'apq8064-tabla-snd-card Headset Jack'.
I/EventHub(  178): New device: id=3, fd=70, path='/dev/input/event4', name='apq8064-tabla-snd-card Headset Jack', classes=0x80, configuration='', keyLayout='', keyCharacterMap='', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true
D/EventHub(  178): No input device configuration file found for device 'apq8064-tabla-snd-card Button Jack'.
W/EventHub(  178): Unable to disable kernel key repeat for /dev/input/event3: Function not implemented
I/EventHub(  178): New device: id=4, fd=71, path='/dev/input/event3', name='apq8064-tabla-snd-card Button Jack', classes=0x1, configuration='', keyLayout='/system/usr/keylayout/apq8064-tabla-snd-card_Button_Jack.kl', keyCharacterMap='/system/usr/keychars/apq8064-tabla-snd-card_Button_Jack.kcm', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true
D/EventHub(  178): No input device configuration file found for device 'hs_detect'.
W/EventHub(  178): Unable to disable kernel key repeat for /dev/input/event5: Function not implemented
I/EventHub(  178): New device: id=5, fd=69, path='/dev/input/event5', name='hs_detect', classes=0x81, configuration='', keyLayout='/system/usr/keylayout/hs_detect.kl', keyCharacterMap='/system/usr/keychars/hs_detect.kcm', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true
I/EventHub(  178): New device: id=6, fd=73, path='/dev/input/event2', name='touch_dev', classes=0x14, configuration='/system/usr/idc/touch_dev.idc', keyLayout='', keyCharacterMap='', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true
I/InputReader(  178): Device added: id=-1, name='Virtual', sources=0x00000301
I/InputReader(  178): Device reconfigured: id=6, name='touch_dev', size 768x1280, orientation 0, mode 1, display id 0
I/InputReader(  178): Device added: id=6, name='touch_dev', sources=0x00001002
I/InputReader(  178): Device added: id=5, name='hs_detect', sources=0x80000101
I/InputReader(  178): Device added: id=4, name='apq8064-tabla-snd-card Button Jack', sources=0x00000101
I/InputReader(  178): Device added: id=3, name='apq8064-tabla-snd-card Headset Jack', sources=0x80000000
I/InputReader(  178): Device added: id=2, name='keypad_8064', sources=0x00000101
I/InputReader(  178): Device added: id=1, name='pmic8xxx_pwrkey', sources=0x00000101
I/HWComposer(  178): Creating new instance
I/qdhwcomposer(  178): hwc_registerProcs
I/qdhwcomposer(  178): Initializing UEVENT Thread
I/qdhwcomposer(  178): Initializing VSYNC Thread
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][OnMaybeDequeueOne] Error: Channel closing: too late to send/recv, messages will be lost
I/Gecko   (  178): 
I/(Nuwa)  (  464): Could not read chrome manifest 'file:///system/b2g/chrome.manifest'.
I/Gecko   (  178): AlarmService: init()
I/Gecko   (  178): AlarmService: _restoreAlarmsFromDb()
W/GeckoConsole(  178): [JavaScript Warning: "Empty string passed to getElementById()." {file: "chrome://b2g/content/shell.html" line: 0}]
I/Gecko   (  178): AlarmService: Callback after getting alarms from database: []
I/Gecko   (  178): AlarmService: Current alarm: null
I/Gecko   (  178): AlarmService: Alarm queue: []
I/Gonk    (  178): Connected to netd
I/Gecko   (  464): ###################################### forms.js loaded
I/Gecko   (  464): ############################### browserElementPanning.js loaded
I/Gecko   (  464): ###################################### BrowserElementCopyPaste.js loaded
I/Gecko   (  464): ######################## BrowserElementChildPreload.js loaded
I/Gonk    (  178): RIL[0]: OnConnectSuccess
W/AudioPolicyManagerBase(  173): setPhoneState() setting same state 0
D/SoftapController(  169): Softap fwReload - Ok
E/BandwidthController(  169): No such iface wlan0 to delete
W/AudioFlinger(  173): Thread AudioOut_3 cannot connect to the power manager service
W/AudioFlinger(  173): Thread AudioOut_2 cannot connect to the power manager service
W/AudioFlinger(  173): Thread AudioOut_3 cannot connect to the power manager service
E/AudioFlinger(  173): no wake lock to update!
W/AudioFlinger(  173): Thread AudioOut_2 cannot connect to the power manager service
E/AudioFlinger(  173): no wake lock to update!
I/        (  178): [b2g
I/Gecko   (  178): Extension error: [Exception... "Failed to open input source 'moz-extension://9d5dee22-4829-4087-b1c1-a3ad1881e1b8/manifest.json'"  nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)"  location: "JS frame :: resource://gre/modules/Extension.jsm :: readJSON/< :: line 594"  data: yes] undefined:594
E/GeckoConsole(  178): [JavaScript Error: "[Exception... "Failed to open input source 'moz-extension://9d5dee22-4829-4087-b1c1-a3ad1881e1b8/manifest.json'"  nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)"  location: "JS frame :: resource://gre/modules/Extension.jsm :: readJSON/< :: line 594"  data: yes]" {file: "resource://gre/modules/Extension.jsm" line: 751}]
I/Gecko   (  178): Extension error: [Exception... "Failed to open input source 'moz-extension://c805f778-9bf0-4899-9a64-eb2841078c4d/manifest.json'"  nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)"  location: "JS frame :: resource://gre/modules/Extension.jsm :: readJSON/< :: line 594"  data: yes] undefined:594
E/GeckoConsole(  178): [JavaScript Error: "[Exception... "Failed to open input source 'moz-extension://c805f778-9bf0-4899-9a64-eb2841078c4d/manifest.json'"  nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)"  location: "JS frame :: resource://gre/modules/Extension.jsm :: readJSON/< :: line 594"  data: yes]" {file: "resource://gre/modules/Extension.jsm" line: 751}]
I/Gecko   (  178): Extension error: [Exception... "Failed to open input source 'moz-extension://9a0cac4b-4e79-48f8-b76d-059a23bafa12/manifest.json'"  nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)"  location: "JS frame :: resource://gre/modules/Extension.jsm :: readJSON/< :: line 594"  data: yes] undefined:594
E/GeckoConsole(  178): [JavaScript Error: "[Exception... "Failed to open input source 'moz-extension://9a0cac4b-4e79-48f8-b76d-059a23bafa12/manifest.json'"  nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)"  location: "JS frame :: resource://gre/modules/Extension.jsm :: readJSON/< :: line 594"  data: yes]" {file: "resource://gre/modules/Extension.jsm" line: 751}]
I/VolumeManager(  178): SetUnmountRequested for volume sdcard to 0 CanBeMounted = 0
I/VolumeManager(  178): SetMountRequested for volume sdcard to 0 CanBeMounted = 0
I/VolumeManager(  178): SetSharingMode for volume sdcard to 1 canBeShared = 0
I/AutoMounter(  178): UpdateState: ums:A0C0E0 mtp:A1C0E0 mode:0 usb:1 tryToShare:0 state:IDLE
I/AutoMounter(  178): UpdateState: Volume sdcard is Mounted and inserted @ /mnt/shell/emulated/0 gen 1 locked 0 sharing x
I/AutoMounter(  178): UpdateState: ums:A0C0E0 mtp:A1C0E0 mode:0 usb:1 tryToShare:0 state:IDLE
I/AutoMounter(  178): UpdateState: Volume sdcard is Mounted and inserted @ /mnt/shell/emulated/0 gen 1 locked 0 sharing x
I/Gecko   (  178): ###################################### forms.js loaded
I/Gecko   (  178): ###################################### BrowserElementCopyPaste.js loaded
I/Gecko   (  178): ############################### browserElementPanning.js loaded
I/Gecko   (  178): ######################## BrowserElementChildPreload.js loaded
I/Gecko   (  178): ######################## extensions.js loaded
I/Gecko   (  178): *** UTM:SVC TimerManager:registerTimer - id: user-agent-updates-timer
I/GeckoConsole(  178): UTM:SVC TimerManager:registerTimer - id: user-agent-updates-timer
I/wpa_supplicant(  766): Successfully initialized wpa_supplicant
I/wpa_supplicant(  766): rfkill: Cannot open RFKILL control device
I/(Preallocated app)(  727): PAC file installed from data: URI
I/Gecko   (  178): XXX FIXME : Dispatch a mozChromeEvent: webapps-registry-ready
I/Gecko   (  178): Attempting load of libEGL.so
D/libEGL  (  178): loaded /system/lib/egl/libEGL_adreno.so
D/libEGL  (  178): loaded /system/lib/egl/libGLESv1_CM_adreno.so
D/libEGL  (  178): loaded /system/lib/egl/libGLESv2_adreno.so
I/Adreno-EGL(  178): : EGL 1.4 QUALCOMM Build: I0404c4692afb8623f95c43aeb6d5e13ed4b30ddbDate: 11/06/13
I/GeckoConsole(  178): OpenGL compositor Initialized Succesfully.
I/GeckoConsole(  178): Version: OpenGL ES 3.0 [email protected] AU@  (CL@)
I/GeckoConsole(  178): Vendor: Qualcomm
I/GeckoConsole(  178): Renderer: Adreno (TM) 320
I/GeckoConsole(  178): FBO Texture Target: TEXTURE_2D
I/Gecko   (  178): XXX FIXME : Dispatch a mozChromeEvent: system-first-paint
I/Gecko   (  178): LogShake.jsm: Disabling QA Mode
I/GeckoDump(  178): AUS:Settings: Not a dogfooder!
I/GeckoDump(  178): AdbController: Starting USB debugger on /data/local/debugger-socket
I/GeckoDump(  178): XXX FIXME : Got a mozContentEvent: system-message-listener-ready
I/Gecko   (  178): XXX FIXME : Dispatch a mozPrefChromeEvent: undefined
I/Gecko   (  727): ######################## extensions.js loaded
W/Default Home Screen(  727): [JavaScript Warning: "Use of nsIFile in content process is deprecated." {file: "jar:file:///system/b2g/omni.ja!/components/DirectoryProvider.js" line: 81}]
W/Default Home Screen(  727): [JavaScript Warning: "Error in parsing value for 'text-align'.  Declaration dropped." {file: "app://homescreen.gaiamobile.org/index.html#root" line: 43 column: 18 source: "      text-align: -moz-start;"}]
W/Default Home Screen(  727): [JavaScript Warning: "Error in parsing value for 'text-align'.  Declaration dropped." {file: "app://homescreen.gaiamobile.org/index.html#root" line: 43 column: 18 source: "      text-align: -moz-start;"}]
D/skia    (  178): START /proc/cpuinfo:
D/skia    (  178): Processor	: ARMv7 Processor rev 2 (v7l)
D/skia    (  178): processor	: 0
D/skia    (  178): BogoMIPS	: 13.53
D/skia    (  178): 
D/skia    (  178): processor	: 1
D/skia    (  178): BogoMIPS	: 13.53
D/skia    (  178): 
D/skia    (  178): processor	: 2
D/skia    (  178): BogoMIPS	: 13.53
D/skia    (  178): 
D/skia    (  178): processor	: 3
D/skia    (  178): BogoMIPS	: 13.53
D/skia    (  178): 
D/skia    (  178): Features	: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 
D/skia    (  178): CPU implementer	: 0x51
D/skia    (  178): CPU architecture: 7
D/skia    (  178): CPU variant	: 0x0
D/skia    (  178): CPU part	: 0x06f
D/skia    (  178): CPU revision	: 2
D/skia    (  178): 
D/skia    (  178): Hardware	: QCT APQ8064 MAKO
D/skia    (  178): Revision	: 000b
D/skia    (  178): Serial		: 0000000000000000
D/skia    (  178): 
D/skia    (  178): END /proc/cpuinfo
D/skia    (  178): Device supports ARM NEON instructions!
E/GeckoConsole(  178): [JavaScript Error: "ConstraintError" {file: "jar:file:///system/b2g/omni.ja!/components/DataStoreImpl.js" line: 233}]
I/libsuspend(  178): Selected early suspend
I/libsuspend(  178): Starting early suspend unblocker thread
E/ANDR-PERF-LOCK(  185): Failed to reset optimization for resource: 4 level: 0
W/qcom_sensors_hal(  178): _hal_sensors_activate: Deactivating dirty sensor 5
W/qcom_sensors_hal(  178): hal_acquire_resources, no active sensors!
I/Gecko   (  178): -*- Nfc: Received message from content process: {"target":{},"name":"NFC:SetFocusTab","sync":false,"json":{"tabId":1,"isFocus":true},"data":{"tabId":1,"isFocus":true},"objects":{}}
I/Gecko   (  178): -*- Nfc: Received message from content process: {"target":{},"name":"NFC:AddEventListener","sync":false,"json":{"tabId":0},"data":{"tabId":0},"objects":{}}
I/Gecko   (  178): -*- Nfc: Received message from content process: {"target":{},"name":"NFC:QueryInfo","sync":true,"json":null,"data":null,"objects":{}}
I/GeckoDump(  178): XXX FIXME : Got a mozContentEvent: update-prompt-ready
I/Gecko   (  178): ###################################### BrowserElementCopyPaste.js loaded
I/Gecko   (  178): ############################### browserElementPanning.js loaded
I/Gecko   (  178): ######################## BrowserElementChildPreload.js loaded
I/Gecko   (  178): ######################## extensions.js loaded
I/Gecko   (  178): -*- Nfc: Received message from content process: {"target":{},"name":"NFC:RegisterPeerReadyTarget","sync":false,"json":{"appId":1},"data":{"appId":1},"objects":{}}
I/GeckoConsole(  178): Content JS LOG: defaultAdapter changed. address: 00:00:00:00:00:00 
I/GeckoConsole(  178):     at onManagerAttributeChanged (app://callscreen.gaiamobile.org/shared/js/bluetooth_helper.js:69:1)
I/GeckoConsole(  178): Content JS LOG: Error handling bluetooth request 
I/GeckoConsole(  178):     at BluetoothHelper/_handleRequest/request.onerror (app://callscreen.gaiamobile.org/shared/js/bluetooth_helper.js:39:7)
E/GeckoConsole(  178): [JavaScript Error: "ConstraintError" {file: "jar:file:///system/b2g/omni.ja!/components/DataStoreImpl.js" line: 233}]
E/GeckoConsole(  178): [JavaScript Error: "ConstraintError" {file: "jar:file:///system/b2g/omni.ja!/components/DataStoreImpl.js" line: 233}]
I/Gecko   (  892): ######################## extensions.js loaded
W/Built-in Keyboard(  892): [JavaScript Warning: "Use of nsIFile in content process is deprecated." {file: "jar:file:///system/b2g/omni.ja!/components/DirectoryProvider.js" line: 81}]
I/Built-in Keyboard(  892): PAC file installed from data: URI
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/GeckoConsole(  178): [JavaScript Error: "ConstraintError" {file: "jar:file:///system/b2g/omni.ja!/components/DataStoreImpl.js" line: 233}]
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/GeckoConsole(  178): [JavaScript Error: "ConstraintError" {file: "jar:file:///system/b2g/omni.ja!/components/DataStoreImpl.js" line: 233}]
I/GeckoConsole(  178): PAC file installed from data: URI
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
I/GeckoDump(  178): XXX FIXME : Got a mozContentEvent: force-update-check
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
E/GeckoConsole(  178): [JavaScript Error: "uncaught exception: [object DOMError]"]
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][DispatchAsyncMessage] Error: (msgtype=0x18001D,name=PBackground::Msg_PBlobConstructor) Value error: message was deserialized, but contained an illegal value
I/Gecko   (  178): 
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][DispatchAsyncMessage] Error: (msgtype=0x1E0003,name=???) Route error: message sent to unknown actor ID
I/Gecko   (  178): 
I/Gecko   (  178): -*- Nfc: Received message from content process: {"target":{},"name":"NFC:ChangeRFState","sync":false,"json":{"requestId":"aWR7NWJkNjI0ODgtMGIzNi00YTdiLWJhMTItNDE5MTQ5ZmQ0ODBkfQ==","rfState":"discovery"},"data":{"requestId":"aWR7NWJkNjI0ODgtMGIzNi00YTdiLWJhMTItNDE5MTQ5ZmQ0ODBkfQ==","rfState":"discovery"},"objects":{}}
I/Gecko   (  178): -*- Nfc: Starting Nfc Service
E/Default Home Screen(  727): Content JS ERROR: Failed to retrieve icon [object DOMError] 
E/Default Home Screen(  727):     at proto.refresh/handleError (app://homescreen.gaiamobile.org/shared/elements/gaia-site-icon/script.js:559:11)
D/skia    (  727): START /proc/cpuinfo:
D/skia    (  727): Processor	: ARMv7 Processor rev 2 (v7l)
D/skia    (  727): processor	: 0
D/skia    (  727): BogoMIPS	: 13.53
D/skia    (  727): 
D/skia    (  727): processor	: 1
D/skia    (  727): BogoMIPS	: 13.53
D/skia    (  727): 
D/skia    (  727): processor	: 2
D/skia    (  727): BogoMIPS	: 13.53
D/skia    (  727): 
D/skia    (  727): processor	: 3
D/skia    (  727): BogoMIPS	: 13.53
D/skia    (  727): 
D/skia    (  727): Features	: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 
D/skia    (  727): CPU implementer	: 0x51
D/skia    (  727): CPU architecture: 7
D/skia    (  727): CPU variant	: 0x0
D/skia    (  727): CPU part	: 0x06f
D/skia    (  727): CPU revision	: 2
D/skia    (  727): 
D/skia    (  727): Hardware	: QCT APQ8064 MAKO
D/skia    (  727): Revision	: 000b
D/skia    (  727): Serial		: 0000000000000000
D/skia    (  727): 
D/skia    (  727): END /proc/cpuinfo
D/skia    (  727): Device supports ARM NEON instructions!
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][DispatchAsyncMessage] Error: (msgtype=0x18001D,name=PBackground::Msg_PBlobConstructor) Value error: message was deserialized, but contained an illegal value
I/Gecko   (  178): 
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][DispatchAsyncMessage] Error: (msgtype=0x1E0003,name=???) Route error: message sent to unknown actor ID
I/Gecko   (  178): 
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][DispatchAsyncMessage] Error: (msgtype=0x18001D,name=PBackground::Msg_PBlobConstructor) Value error: message was deserialized, but contained an illegal value
I/Gecko   (  178): 
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][DispatchAsyncMessage] Error: (msgtype=0x1E0003,name=???) Route error: message sent to unknown actor ID
I/Gecko   (  178): 
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][DispatchAsyncMessage] Error: (msgtype=0x18001D,name=PBackground::Msg_PBlobConstructor) Value error: message was deserialized, but contained an illegal value
I/Gecko   (  178): 
I/Gecko   (  178): 
I/Gecko   (  178): ###!!! [Parent][DispatchAsyncMessage] Error: (msgtype=0x1E0003,name=???) Route error: message sent to unknown actor ID
I/Gecko   (  178): 
I/(Preallocated app)( 1124): PAC file installed from data: URI
D/Default Home Screen(  727): Content JS DEBUG: Bug 1211266: getIcon retry 1 for app://test-ime.gaiamobile.org/manifest.webapp 
D/Default Home Screen(  727):     at proto.refresh/getImage/

 

 

#####################################################################################################

https://blog.csdn.net/hunter___/article/details/81059887#comments

你的问题我看了一下,疑问如下:

1.gdb 是你自己打的吗?

2.你修改源码/media/bingco/DATA_WIN/B2G/gecko/ipc/glue/MessageChannel.cpp, line 2057 了吗?看起似乎是你想用gdb 调试,然后到这里断了???

3.如果你没有自己gdb 那么就是你用的那份源码之前的人打过log,做过gdb相关的操作。建议换一个源码试试。我把

/media/bingco/DATA_WIN/B2G/gecko/ipc/glue/MessageChannel.cpp,文件给你附下面。你先对比一下差异,有差异就替换一下试试。

4.出现这种 Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 1100 (Compositor) 据网友经验可能有好几个原因,

1)头文件路径 ,编译环境发现,用到的头文件位置不同,导致结果差异。通过重新设置头文件路径。

https://www.cnblogs.com/Sharley/p/6605347.html  感觉 跟你的比较相似,文件路径。编译环境问题。

2)机器太老

3)你自己的库有问题,。。。

我感觉是你gdb那里的问题,具体报了文件名了都

参考:

https://blog.csdn.net/feng5219/article/details/50324677

 

 

 

回复itatoo_第5张图片

你的文件2057行有啥?

回复itatoo_第6张图片

 

源码:

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: sw=4 ts=4 et :
 */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/ipc/MessageChannel.h"
#include "mozilla/ipc/ProtocolUtils.h"

#include "mozilla/dom/ScriptSettings.h"

#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Move.h"
#include "mozilla/SizePrintfMacros.h"
#include "mozilla/Telemetry.h"
#include "nsDebug.h"
#include "nsISupportsImpl.h"
#include "nsContentUtils.h"

#include "prprf.h"

// Undo the damage done by mozzconf.h
#undef compress

/*
 * IPC design:
 *
 * There are three kinds of messages: async, sync, and intr. Sync and intr
 * messages are blocking. Only intr and high-priority sync messages can nest.
 *
 * Terminology: To dispatch a message Foo is to run the RecvFoo code for
 * it. This is also called "handling" the message.
 *
 * Sync and async messages have priorities while intr messages always have
 * normal priority. The three possible priorities are normal, high, and urgent.
 * The intended uses of these priorities are:
 *   NORMAL - most messages.
 *   HIGH   - CPOW-related messages, which can go in either direction.
 *   URGENT - messages where we don't want to dispatch
 *            incoming CPOWs while waiting for the response.
 * Async messages cannot have HIGH priority.
 *
 * To avoid jank, the parent process is not allowed to send sync messages of
 * normal priority. When a process is waiting for a response to a sync message
 * M0, it will dispatch an incoming message M if:
 *   1. M has a higher priority than M0, or
 *   2. if M has the same priority as M0 and we're in the child, or
 *   3. if M has the same priority as M0 and it was sent by the other side
 *      while dispatching M0 (nesting).
 * The idea is that higher priority messages should take precendence, and we
 * also want to allow nesting. The purpose of rule 2 is to handle a race where
 * both processes send to each other simultaneously. In this case, we resolve
 * the race in favor of the parent (so the child dispatches first).
 *
 * Messages satisfy the following properties:
 *   A. When waiting for a response to a sync message, we won't dispatch any
 *      messages of lower priority.
 *   B. Messages of the same priority will be dispatched roughly in the
 *      order they were sent. The exception is when the parent and child send
 *      sync messages to each other simulataneously. In this case, the parent's
 *      message is dispatched first. While it is dispatched, the child may send
 *      further nested messages, and these messages may be dispatched before the
 *      child's original message. We can consider ordering to be preserved here
 *      because we pretend that the child's original message wasn't sent until
 *      after the parent's message is finished being dispatched.
 *
 * When waiting for a sync message reply, we dispatch an async message only if
 * it has URGENT priority. Normally URGENT async messages are sent only from the
 * child. However, the parent can send URGENT async messages when it is creating
 * a bridged protocol.
 *
 * Intr messages are blocking but not prioritized. While waiting for an intr
 * response, all incoming messages are dispatched until a response is
 * received. Intr messages also can be nested. When two intr messages race with
 * each other, a similar scheme is used to ensure that one side wins. The
 * winning side is chosen based on the message type.
 *
 * Intr messages differ from sync messages in that, while sending an intr
 * message, we may dispatch an async message. This causes some additional
 * complexity. One issue is that replies can be received out of order. It's also
 * more difficult to determine whether one message is nested inside
 * another. Consequently, intr handling uses mOutOfTurnReplies and
 * mRemoteStackDepthGuess, which are not needed for sync messages.
 */

using namespace mozilla;
using namespace std;

using mozilla::dom::AutoNoJSAPI;
using mozilla::dom::ScriptSettingsInitialized;
using mozilla::MonitorAutoLock;
using mozilla::MonitorAutoUnlock;

template<>
struct RunnableMethodTraits
{
    static void RetainCallee(mozilla::ipc::MessageChannel* obj) { }
    static void ReleaseCallee(mozilla::ipc::MessageChannel* obj) { }
};

#define IPC_ASSERT(_cond, ...)                                      \
    do {                                                            \
        if (!(_cond))                                               \
            DebugAbort(__FILE__, __LINE__, #_cond,## __VA_ARGS__);  \
    } while (0)

static MessageChannel* gParentProcessBlocker;

namespace mozilla {
namespace ipc {

const int32_t MessageChannel::kNoTimeout = INT32_MIN;

// static
bool MessageChannel::sIsPumpingMessages = false;

enum Direction
{
    IN_MESSAGE,
    OUT_MESSAGE
};

class MessageChannel::InterruptFrame
{
private:
    enum Semantics
    {
        INTR_SEMS,
        SYNC_SEMS,
        ASYNC_SEMS
    };

public:
    InterruptFrame(Direction direction, const Message* msg)
      : mMessageName(strdup(msg->name())),
        mMessageRoutingId(msg->routing_id()),
        mMesageSemantics(msg->is_interrupt() ? INTR_SEMS :
                          msg->is_sync() ? SYNC_SEMS :
                          ASYNC_SEMS),
        mDirection(direction),
        mMoved(false)
    {
        MOZ_ASSERT(mMessageName);
    }

    InterruptFrame(InterruptFrame&& aOther)
    {
        MOZ_ASSERT(aOther.mMessageName);
        mMessageName = aOther.mMessageName;
        aOther.mMessageName = nullptr;
        aOther.mMoved = true;

        mMessageRoutingId = aOther.mMessageRoutingId;
        mMesageSemantics = aOther.mMesageSemantics;
        mDirection = aOther.mDirection;
    }

    ~InterruptFrame()
    {
        MOZ_ASSERT_IF(!mMessageName, mMoved);

        if (mMessageName)
            free(const_cast(mMessageName));
    }

    InterruptFrame& operator=(InterruptFrame&& aOther)
    {
        MOZ_RELEASE_ASSERT(&aOther != this);
        this->~InterruptFrame();
        new (this) InterruptFrame(mozilla::Move(aOther));
        return *this;
    }

    bool IsInterruptIncall() const
    {
        return INTR_SEMS == mMesageSemantics && IN_MESSAGE == mDirection;
    }

    bool IsInterruptOutcall() const
    {
        return INTR_SEMS == mMesageSemantics && OUT_MESSAGE == mDirection;
    }

    bool IsOutgoingSync() const {
        return (mMesageSemantics == INTR_SEMS || mMesageSemantics == SYNC_SEMS) &&
               mDirection == OUT_MESSAGE;
    }

    void Describe(int32_t* id, const char** dir, const char** sems,
                  const char** name) const
    {
        *id = mMessageRoutingId;
        *dir = (IN_MESSAGE == mDirection) ? "in" : "out";
        *sems = (INTR_SEMS == mMesageSemantics) ? "intr" :
                (SYNC_SEMS == mMesageSemantics) ? "sync" :
                "async";
        *name = mMessageName;
    }

    int32_t GetRoutingId() const
    {
        return mMessageRoutingId;
    }

private:
    const char* mMessageName;
    int32_t mMessageRoutingId;
    Semantics mMesageSemantics;
    Direction mDirection;
    DebugOnly mMoved;

    // Disable harmful methods.
    InterruptFrame(const InterruptFrame& aOther) = delete;
    InterruptFrame& operator=(const InterruptFrame&) = delete;
};

class MOZ_STACK_CLASS MessageChannel::CxxStackFrame
{
public:
    CxxStackFrame(MessageChannel& that, Direction direction, const Message* msg)
      : mThat(that)
    {
        mThat.AssertWorkerThread();

        if (mThat.mCxxStackFrames.empty())
            mThat.EnteredCxxStack();

        mThat.mCxxStackFrames.append(InterruptFrame(direction, msg));

        const InterruptFrame& frame = mThat.mCxxStackFrames.back();

        if (frame.IsInterruptIncall())
            mThat.EnteredCall();

        if (frame.IsOutgoingSync())
            mThat.EnteredSyncSend();

        mThat.mSawInterruptOutMsg |= frame.IsInterruptOutcall();
    }

    ~CxxStackFrame() {
        mThat.AssertWorkerThread();

        MOZ_ASSERT(!mThat.mCxxStackFrames.empty());

        const InterruptFrame& frame = mThat.mCxxStackFrames.back();
        bool exitingSync = frame.IsOutgoingSync();
        bool exitingCall = frame.IsInterruptIncall();
        mThat.mCxxStackFrames.shrinkBy(1);

        bool exitingStack = mThat.mCxxStackFrames.empty();

        // mListener could have gone away if Close() was called while
        // MessageChannel code was still on the stack
        if (!mThat.mListener)
            return;

        if (exitingCall)
            mThat.ExitedCall();

        if (exitingSync)
            mThat.ExitedSyncSend();

        if (exitingStack)
            mThat.ExitedCxxStack();
    }
private:
    MessageChannel& mThat;

    // Disable harmful methods.
    CxxStackFrame() = delete;
    CxxStackFrame(const CxxStackFrame&) = delete;
    CxxStackFrame& operator=(const CxxStackFrame&) = delete;
};

namespace {

class MOZ_RAII MaybeScriptBlocker {
public:
    explicit MaybeScriptBlocker(MessageChannel *aChannel, bool aBlock
                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
        : mBlocked(aChannel->ShouldBlockScripts() && aBlock)
    {
        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
        if (mBlocked) {
            nsContentUtils::AddScriptBlocker();
        }
    }
    ~MaybeScriptBlocker() {
        if (mBlocked) {
            nsContentUtils::RemoveScriptBlocker();
        }
    }
private:
    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    bool mBlocked;
};

} // namespace

MessageChannel::MessageChannel(MessageListener *aListener)
  : mListener(aListener),
    mChannelState(ChannelClosed),
    mSide(UnknownSide),
    mLink(nullptr),
    mWorkerLoop(nullptr),
    mChannelErrorTask(nullptr),
    mWorkerLoopID(-1),
    mTimeoutMs(kNoTimeout),
    mInTimeoutSecondHalf(false),
    mNextSeqno(0),
    mAwaitingSyncReply(false),
    mAwaitingSyncReplyPriority(0),
    mDispatchingSyncMessage(false),
    mDispatchingSyncMessagePriority(0),
    mDispatchingAsyncMessage(false),
    mDispatchingAsyncMessagePriority(0),
    mCurrentTransaction(0),
    mTimedOutMessageSeqno(0),
    mTimedOutMessagePriority(0),
    mRecvdErrors(0),
    mRemoteStackDepthGuess(false),
    mSawInterruptOutMsg(false),
    mIsWaitingForIncoming(false),
    mAbortOnError(false),
    mBlockScripts(false),
    mFlags(REQUIRE_DEFAULT),
    mPeerPidSet(false),
    mPeerPid(-1)
{
    MOZ_COUNT_CTOR(ipc::MessageChannel);

#ifdef OS_WIN
    mTopFrame = nullptr;
    mIsSyncWaitingOnNonMainThread = false;
#endif

    mDequeueOneTask = new RefCountedTask(NewRunnableMethod(
                                                 this,
                                                 &MessageChannel::OnMaybeDequeueOne));

    mOnChannelConnectedTask = new RefCountedTask(NewRunnableMethod(
        this,
        &MessageChannel::DispatchOnChannelConnected));

#ifdef OS_WIN
    mEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
    NS_ASSERTION(mEvent, "CreateEvent failed! Nothing is going to work!");
#endif
}

MessageChannel::~MessageChannel()
{
    MOZ_COUNT_DTOR(ipc::MessageChannel);
    IPC_ASSERT(mCxxStackFrames.empty(), "mismatched CxxStackFrame ctor/dtors");
#ifdef OS_WIN
    DebugOnly ok = CloseHandle(mEvent);
    MOZ_ASSERT(ok);
#endif
    Clear();
}

static void
PrintErrorMessage(Side side, const char* channelName, const char* msg)
{
    const char *from = (side == ChildSide)
                       ? "Child"
                       : ((side == ParentSide) ? "Parent" : "Unknown");
    printf_stderr("\n###!!! [%s][%s] Error: %s\n\n", from, channelName, msg);
}

bool
MessageChannel::Connected() const
{
    mMonitor->AssertCurrentThreadOwns();

    // The transport layer allows us to send messages before
    // receiving the "connected" ack from the remote side.
    return (ChannelOpening == mChannelState || ChannelConnected == mChannelState);
}

bool
MessageChannel::CanSend() const
{
    if (!mMonitor) {
        return false;
    }
    MonitorAutoLock lock(*mMonitor);
    return Connected();
}

void
MessageChannel::Clear()
{
    // Don't clear mWorkerLoopID; we use it in AssertLinkThread() and
    // AssertWorkerThread().
    //
    // Also don't clear mListener.  If we clear it, then sending a message
    // through this channel after it's Clear()'ed can cause this process to
    // crash.
    //
    // In practice, mListener owns the channel, so the channel gets deleted
    // before mListener.  But just to be safe, mListener is a weak pointer.

    if (gParentProcessBlocker == this) {
        gParentProcessBlocker = nullptr;
    }

    mDequeueOneTask->Cancel();

    mWorkerLoop = nullptr;
    delete mLink;
    mLink = nullptr;

    mOnChannelConnectedTask->Cancel();

    if (mChannelErrorTask) {
        mChannelErrorTask->Cancel();
        mChannelErrorTask = nullptr;
    }

    // Free up any memory used by pending messages.
    mPending.clear();
    mRecvd = nullptr;
    mOutOfTurnReplies.clear();
    while (!mDeferred.empty()) {
        mDeferred.pop();
    }
}

bool
MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
{
    NS_PRECONDITION(!mLink, "Open() called > once");

    mMonitor = new RefCountedMonitor();
    mWorkerLoop = MessageLoop::current();
    mWorkerLoopID = mWorkerLoop->id();

    ProcessLink *link = new ProcessLink(this);
    link->Open(aTransport, aIOLoop, aSide); // :TODO: n.b.: sets mChild
    mLink = link;
    return true;
}

bool
MessageChannel::Open(MessageChannel *aTargetChan, MessageLoop *aTargetLoop, Side aSide)
{
    // Opens a connection to another thread in the same process.

    //  This handshake proceeds as follows:
    //  - Let A be the thread initiating the process (either child or parent)
    //    and B be the other thread.
    //  - A spawns thread for B, obtaining B's message loop
    //  - A creates ProtocolChild and ProtocolParent instances.
    //    Let PA be the one appropriate to A and PB the side for B.
    //  - A invokes PA->Open(PB, ...):
    //    - set state to mChannelOpening
    //    - this will place a work item in B's worker loop (see next bullet)
    //      and then spins until PB->mChannelState becomes mChannelConnected
    //    - meanwhile, on PB's worker loop, the work item is removed and:
    //      - invokes PB->SlaveOpen(PA, ...):
    //        - sets its state and that of PA to Connected
    NS_PRECONDITION(aTargetChan, "Need a target channel");
    NS_PRECONDITION(ChannelClosed == mChannelState, "Not currently closed");

    CommonThreadOpenInit(aTargetChan, aSide);

    Side oppSide = UnknownSide;
    switch(aSide) {
      case ChildSide: oppSide = ParentSide; break;
      case ParentSide: oppSide = ChildSide; break;
      case UnknownSide: break;
    }

    mMonitor = new RefCountedMonitor();

    MonitorAutoLock lock(*mMonitor);
    mChannelState = ChannelOpening;
    aTargetLoop->PostTask(
        FROM_HERE,
        NewRunnableMethod(aTargetChan, &MessageChannel::OnOpenAsSlave, this, oppSide));

    while (ChannelOpening == mChannelState)
        mMonitor->Wait();
    NS_ASSERTION(ChannelConnected == mChannelState, "not connected when awoken");
    return (ChannelConnected == mChannelState);
}

void
MessageChannel::OnOpenAsSlave(MessageChannel *aTargetChan, Side aSide)
{
    // Invoked when the other side has begun the open.
    NS_PRECONDITION(ChannelClosed == mChannelState,
                    "Not currently closed");
    NS_PRECONDITION(ChannelOpening == aTargetChan->mChannelState,
                    "Target channel not in the process of opening");

    CommonThreadOpenInit(aTargetChan, aSide);
    mMonitor = aTargetChan->mMonitor;

    MonitorAutoLock lock(*mMonitor);
    NS_ASSERTION(ChannelOpening == aTargetChan->mChannelState,
                 "Target channel not in the process of opening");
    mChannelState = ChannelConnected;
    aTargetChan->mChannelState = ChannelConnected;
    aTargetChan->mMonitor->Notify();
}

void
MessageChannel::CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide)
{
    mWorkerLoop = MessageLoop::current();
    mWorkerLoopID = mWorkerLoop->id();
    mLink = new ThreadLink(this, aTargetChan);
    mSide = aSide;
}

bool
MessageChannel::Echo(Message* aMsg)
{
    nsAutoPtr msg(aMsg);
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();
    if (MSG_ROUTING_NONE == msg->routing_id()) {
        ReportMessageRouteError("MessageChannel::Echo");
        return false;
    }

    MonitorAutoLock lock(*mMonitor);

    if (!Connected()) {
        ReportConnectionError("MessageChannel", msg);
        return false;
    }

    mLink->EchoMessage(msg.forget());
    return true;
}

bool
MessageChannel::Send(Message* aMsg)
{
    CxxStackFrame frame(*this, OUT_MESSAGE, aMsg);

    nsAutoPtr msg(aMsg);
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();
    if (MSG_ROUTING_NONE == msg->routing_id()) {
        ReportMessageRouteError("MessageChannel::Send");
        return false;
    }

    MonitorAutoLock lock(*mMonitor);
    if (!Connected()) {
        ReportConnectionError("MessageChannel", msg);
        return false;
    }
    mLink->SendMessage(msg.forget());
    return true;
}

class CancelMessage : public IPC::Message
{
public:
    CancelMessage() :
        IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE, PRIORITY_NORMAL)
    {
    }
    static bool Read(const Message* msg) {
        return true;
    }
    void Log(const std::string& aPrefix, FILE* aOutf) const {
        fputs("(special `Cancel' message)", aOutf);
    }
};

bool
MessageChannel::MaybeInterceptSpecialIOMessage(const Message& aMsg)
{
    AssertLinkThread();
    mMonitor->AssertCurrentThreadOwns();

    if (MSG_ROUTING_NONE == aMsg.routing_id()) {
        if (GOODBYE_MESSAGE_TYPE == aMsg.type()) {
            // :TODO: Sort out Close() on this side racing with Close() on the
            // other side
            mChannelState = ChannelClosing;
            if (LoggingEnabled()) {
                printf("NOTE: %s process received `Goodbye', closing down\n",
                       (mSide == ChildSide) ? "child" : "parent");
            }
            return true;
        } else if (CANCEL_MESSAGE_TYPE == aMsg.type()) {
            CancelCurrentTransactionInternal();
            NotifyWorkerThread();
            return true;
        }
    }
    return false;
}

bool
MessageChannel::ShouldDeferMessage(const Message& aMsg)
{
    // Never defer messages that have the highest priority, even async
    // ones. This is safe because only the child can send these messages, so
    // they can never nest.
    if (aMsg.priority() == IPC::Message::PRIORITY_URGENT)
        return false;

    // Unless they're urgent, we always defer async messages.
    if (!aMsg.is_sync()) {
        MOZ_ASSERT(aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
        return true;
    }

    int msgPrio = aMsg.priority();
    int waitingPrio = AwaitingSyncReplyPriority();

    // Always defer if the priority of the incoming message is less than the
    // priority of the message we're awaiting.
    if (msgPrio < waitingPrio)
        return true;

    // Never defer if the message has strictly greater priority.
    if (msgPrio > waitingPrio)
        return false;

    // When both sides send sync messages of the same priority, we resolve the
    // race by dispatching in the child and deferring the incoming message in
    // the parent. However, the parent still needs to dispatch nested sync
    // messages.
    //
    // Deferring in the parent only sort of breaks message ordering. When the
    // child's message comes in, we can pretend the child hasn't quite
    // finished sending it yet. Since the message is sync, we know that the
    // child hasn't moved on yet.
    return mSide == ParentSide && aMsg.transaction_id() != mCurrentTransaction;
}

// Predicate that is true for messages that should be consolidated if 'compress' is set.
class MatchingKinds {
    typedef IPC::Message Message;
    Message::msgid_t mType;
    int32_t mRoutingId;
public:
    MatchingKinds(Message::msgid_t aType, int32_t aRoutingId) :
        mType(aType), mRoutingId(aRoutingId) {}
    bool operator()(const Message &msg) {
        return msg.type() == mType && msg.routing_id() == mRoutingId;
    }
};

void
MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
{
    AssertLinkThread();
    mMonitor->AssertCurrentThreadOwns();

    if (MaybeInterceptSpecialIOMessage(aMsg))
        return;

    // Regardless of the Interrupt stack, if we're awaiting a sync reply,
    // we know that it needs to be immediately handled to unblock us.
    if (aMsg.is_sync() && aMsg.is_reply()) {
        if (aMsg.seqno() == mTimedOutMessageSeqno) {
            // Drop the message, but allow future sync messages to be sent.
            mTimedOutMessageSeqno = 0;
            return;
        }

        MOZ_ASSERT(aMsg.transaction_id() == mCurrentTransaction);
        MOZ_ASSERT(AwaitingSyncReply());
        MOZ_ASSERT(!mRecvd);

        // Rather than storing errors in mRecvd, we mark them in
        // mRecvdErrors. We need a counter because multiple replies can arrive
        // when a timeout happens, as in the following example. Imagine the
        // child is running slowly. The parent sends a sync message P1. It times
        // out. The child eventually sends a sync message C1. While waiting for
        // the C1 response, the child dispatches P1. In doing so, it sends sync
        // message C2. At that point, it's valid for the parent to send error
        // responses for both C1 and C2.
        if (aMsg.is_reply_error()) {
            mRecvdErrors++;
            NotifyWorkerThread();
            return;
        }

        mRecvd = new Message(aMsg);
        NotifyWorkerThread();
        return;
    }

    // Prioritized messages cannot be compressed.
    MOZ_ASSERT_IF(aMsg.compress_type() != IPC::Message::COMPRESSION_NONE,
                  aMsg.priority() == IPC::Message::PRIORITY_NORMAL);

    bool compress = false;
    if (aMsg.compress_type() == IPC::Message::COMPRESSION_ENABLED) {
        compress = (!mPending.empty() &&
                    mPending.back().type() == aMsg.type() &&
                    mPending.back().routing_id() == aMsg.routing_id());
        if (compress) {
            // This message type has compression enabled, and the back of the
            // queue was the same message type and routed to the same destination.
            // Replace it with the newer message.
            MOZ_ASSERT(mPending.back().compress_type() ==
                       IPC::Message::COMPRESSION_ENABLED);
            mPending.pop_back();
        }
    } else if (aMsg.compress_type() == IPC::Message::COMPRESSION_ALL) {
        // Check the message queue for another message with this type/destination.
        auto it = std::find_if(mPending.rbegin(), mPending.rend(),
                               MatchingKinds(aMsg.type(), aMsg.routing_id()));
        if (it != mPending.rend()) {
            // This message type has compression enabled, and the queue holds
            // a message with the same message type and routed to the same destination.
            // Erase it.  Note that, since we always compress these redundancies, There Can
            // Be Only One.
            compress = true;
            MOZ_ASSERT((*it).compress_type() == IPC::Message::COMPRESSION_ALL);
            mPending.erase((++it).base());
        }
    }

    bool shouldWakeUp = AwaitingInterruptReply() ||
                        (AwaitingSyncReply() && !ShouldDeferMessage(aMsg)) ||
                        AwaitingIncomingMessage();

    // There are three cases we're concerned about, relating to the state of the
    // main thread:
    //
    // (1) We are waiting on a sync reply - main thread is blocked on the
    //     IPC monitor.
    //   - If the message is high priority, we wake up the main thread to
    //     deliver the message depending on ShouldDeferMessage. Otherwise, we
    //     leave it in the mPending queue, posting a task to the main event
    //     loop, where it will be processed once the synchronous reply has been
    //     received.
    //
    // (2) We are waiting on an Interrupt reply - main thread is blocked on the
    //     IPC monitor.
    //   - Always notify and wake up the main thread.
    //
    // (3) We are not waiting on a reply.
    //   - We post a task to the main event loop.
    //
    // Note that, we may notify the main thread even though the monitor is not
    // blocked. This is okay, since we always check for pending events before
    // blocking again.

    mPending.push_back(aMsg);

    if (shouldWakeUp) {
        NotifyWorkerThread();
    } else {
        // Worker thread is either not blocked on a reply, or this is an
        // incoming Interrupt that raced with outgoing sync, and needs to be
        // deferred to a later event-loop iteration.
        if (!compress) {
            // If we compressed away the previous message, we'll re-use
            // its pending task.
            mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
        }
    }
}

void
MessageChannel::ProcessPendingRequests()
{
    // Loop until there aren't any more priority messages to process.
    for (;;) {
        mozilla::Vector toProcess;

        for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
            Message &msg = *it;
            if (!ShouldDeferMessage(msg)) {
                toProcess.append(Move(msg));
                it = mPending.erase(it);
                continue;
            }
            it++;
        }

        if (toProcess.empty())
            break;

        // Processing these messages could result in more messages, so we
        // loop around to check for more afterwards.
        for (auto it = toProcess.begin(); it != toProcess.end(); it++)
            ProcessPendingRequest(*it);
    }
}

bool
MessageChannel::WasTransactionCanceled(int transaction, int prio)
{
    if (transaction == mCurrentTransaction) {
        return false;
    }

    // This isn't an assert so much as an intentional crash because we're in a
    // situation that we don't know how to recover from: The child is awaiting
    // a reply to a normal-priority sync message. The transaction that this
    // message initiated has now been canceled. That could only happen if a CPOW
    // raced with the sync message and was dispatched by the child while the
    // child was awaiting the sync reply; at some point while dispatching the
    // CPOW, the transaction was canceled.
    //
    // Notes:
    //
    // 1. We don't want to cancel the normal-priority sync message along with
    // the CPOWs because the browser relies on these messages working
    // reliably.
    //
    // 2. Ideally we would like to avoid dispatching CPOWs while awaiting a sync
    // response. This isn't possible though. To avoid deadlock, the parent would
    // have to dispatch the sync message while waiting for the CPOW
    // response. However, it wouldn't have dispatched async messages at that
    // time, so we would have a message ordering bug. Dispatching the async
    // messages first causes other hard-to-handle situations (what if they send
    // CPOWs?).
    //
    // 3. We would like to be able to cancel the CPOWs but not the sync
    // message. However, that would leave both the parent and the child running
    // code at the same time, all while the sync message is still
    // outstanding. That can cause a problem where message replies are received
    // out of order.
    IPC_ASSERT(prio != IPC::Message::PRIORITY_NORMAL,
               "Intentional crash: We canceled a CPOW that was racing with a sync message.");

    return true;
}

bool
MessageChannel::Send(Message* aMsg, Message* aReply)
{
    nsAutoPtr msg(aMsg);

    // See comment in DispatchSyncMessage.
    MaybeScriptBlocker scriptBlocker(this, true);

    // Sanity checks.
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();

    if (mCurrentTransaction == 0)
        mListener->OnBeginSyncTransaction();

#ifdef OS_WIN
    SyncStackFrame frame(this, false);
    NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
#endif

    CxxStackFrame f(*this, OUT_MESSAGE, msg);

    MonitorAutoLock lock(*mMonitor);

    if (mTimedOutMessageSeqno) {
        // Don't bother sending another sync message if a previous one timed out
        // and we haven't received a reply for it. Once the original timed-out
        // message receives a reply, we'll be able to send more sync messages
        // again.
        return false;
    }

    if (mCurrentTransaction &&
        DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_NORMAL &&
        msg->priority() > IPC::Message::PRIORITY_NORMAL)
    {
        // Don't allow sending CPOWs while we're dispatching a sync message.
        // If you want to do that, use sendRpcMessage instead.
        return false;
    }

    if (mCurrentTransaction &&
        (msg->priority() < DispatchingSyncMessagePriority() ||
         mAwaitingSyncReplyPriority > msg->priority()))
    {
        CancelCurrentTransactionInternal();
        mLink->SendMessage(new CancelMessage());
    }

    IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here");

    if (mCurrentTransaction) {
        IPC_ASSERT(msg->priority() >= DispatchingSyncMessagePriority(),
                   "can't send sync message of a lesser priority than what's being dispatched");
        IPC_ASSERT(AwaitingSyncReplyPriority() <= msg->priority(),
                   "nested sync message sends must be of increasing priority");
        IPC_ASSERT(DispatchingSyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
                   "not allowed to send messages while dispatching urgent messages");
    }

    IPC_ASSERT(DispatchingAsyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
               "not allowed to send messages while dispatching urgent messages");

    if (!Connected()) {
        ReportConnectionError("MessageChannel::SendAndWait", msg);
        return false;
    }

    msg->set_seqno(NextSeqno());

    int32_t seqno = msg->seqno();
    int prio = msg->priority();
    DebugOnly replyType = msg->type() + 1;

    AutoSetValue replies(mAwaitingSyncReply, true);
    AutoSetValue prioSet(mAwaitingSyncReplyPriority, prio);
    AutoEnterTransaction transact(this, seqno);

    int32_t transaction = mCurrentTransaction;
    msg->set_transaction_id(transaction);

    ProcessPendingRequests();
    if (WasTransactionCanceled(transaction, prio)) {
        return false;
    }

    bool handleWindowsMessages = mListener->HandleWindowsMessages(*aMsg);
    mLink->SendMessage(msg.forget());

    while (true) {
        ProcessPendingRequests();
        if (WasTransactionCanceled(transaction, prio)) {
            return false;
        }

        // See if we've received a reply.
        if (mRecvdErrors) {
            mRecvdErrors--;
            return false;
        }

        if (mRecvd) {
            break;
        }

        MOZ_ASSERT(!mTimedOutMessageSeqno);

        bool maybeTimedOut = !WaitForSyncNotify(handleWindowsMessages);

        if (!Connected()) {
            ReportConnectionError("MessageChannel::SendAndWait");
            return false;
        }

        if (WasTransactionCanceled(transaction, prio)) {
            return false;
        }

        // We only time out a message if it initiated a new transaction (i.e.,
        // if neither side has any other message Sends on the stack).
        bool canTimeOut = transaction == seqno;
        if (maybeTimedOut && canTimeOut && !ShouldContinueFromTimeout()) {
            // We might have received a reply during WaitForSyncNotify or inside
            // ShouldContinueFromTimeout (which drops the lock). We need to make
            // sure not to set mTimedOutMessageSeqno if that happens, since then
            // there would be no way to unset it.
            if (mRecvdErrors) {
                mRecvdErrors--;
                return false;
            }
            if (mRecvd) {
                break;
            }

            mTimedOutMessageSeqno = seqno;
            mTimedOutMessagePriority = prio;
            return false;
        }
    }

    MOZ_ASSERT(mRecvd);
    MOZ_ASSERT(mRecvd->is_reply(), "expected reply");
    MOZ_ASSERT(!mRecvd->is_reply_error());
    MOZ_ASSERT(mRecvd->type() == replyType, "wrong reply type");
    MOZ_ASSERT(mRecvd->seqno() == seqno);
    MOZ_ASSERT(mRecvd->is_sync());

    *aReply = Move(*mRecvd);
    mRecvd = nullptr;
    return true;
}

bool
MessageChannel::Call(Message* aMsg, Message* aReply)
{
    nsAutoPtr msg(aMsg);
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();

#ifdef OS_WIN
    SyncStackFrame frame(this, true);
#endif

    // This must come before MonitorAutoLock, as its destructor acquires the
    // monitor lock.
    CxxStackFrame cxxframe(*this, OUT_MESSAGE, msg);

    MonitorAutoLock lock(*mMonitor);
    if (!Connected()) {
        ReportConnectionError("MessageChannel::Call", msg);
        return false;
    }

    // Sanity checks.
    IPC_ASSERT(!AwaitingSyncReply(),
               "cannot issue Interrupt call while blocked on sync request");
    IPC_ASSERT(!DispatchingSyncMessage(),
               "violation of sync handler invariant");
    IPC_ASSERT(msg->is_interrupt(), "can only Call() Interrupt messages here");

    msg->set_seqno(NextSeqno());
    msg->set_interrupt_remote_stack_depth_guess(mRemoteStackDepthGuess);
    msg->set_interrupt_local_stack_depth(1 + InterruptStackDepth());
    mInterruptStack.push(*msg);
    mLink->SendMessage(msg.forget());

    while (true) {
        // if a handler invoked by *Dispatch*() spun a nested event
        // loop, and the connection was broken during that loop, we
        // might have already processed the OnError event. if so,
        // trying another loop iteration will be futile because
        // channel state will have been cleared
        if (!Connected()) {
            ReportConnectionError("MessageChannel::Call");
            return false;
        }

#ifdef OS_WIN
        // We need to limit the scoped of neuteredRgn to this spot in the code.
        // Window neutering can't be enabled during some plugin calls because
        // we then risk the neutered window procedure being subclassed by a
        // plugin.
        {
            NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
            /* We should pump messages at this point to ensure that the IPC peer
               does not become deadlocked on a pending inter-thread SendMessage() */
            neuteredRgn.PumpOnce();
        }
#endif

        // Now might be the time to process a message deferred because of race
        // resolution.
        MaybeUndeferIncall();

        // Wait for an event to occur.
        while (!InterruptEventOccurred()) {
            bool maybeTimedOut = !WaitForInterruptNotify();

            // We might have received a "subtly deferred" message in a nested
            // loop that it's now time to process.
            if (InterruptEventOccurred() ||
                (!maybeTimedOut && (!mDeferred.empty() || !mOutOfTurnReplies.empty())))
            {
                break;
            }

            if (maybeTimedOut && !ShouldContinueFromTimeout())
                return false;
        }

        Message recvd;
        MessageMap::iterator it;

        if ((it = mOutOfTurnReplies.find(mInterruptStack.top().seqno()))
            != mOutOfTurnReplies.end())
        {
            recvd = Move(it->second);
            mOutOfTurnReplies.erase(it);
        } else if (!mPending.empty()) {
            recvd = Move(mPending.front());
            mPending.pop_front();
        } else {
            // because of subtleties with nested event loops, it's possible
            // that we got here and nothing happened.  or, we might have a
            // deferred in-call that needs to be processed.  either way, we
            // won't break the inner while loop again until something new
            // happens.
            continue;
        }

        // If the message is not Interrupt, we can dispatch it as normal.
        if (!recvd.is_interrupt()) {
            DispatchMessage(recvd);
            if (!Connected()) {
                ReportConnectionError("MessageChannel::DispatchMessage");
                return false;
            }
            continue;
        }

        // If the message is an Interrupt reply, either process it as a reply to our
        // call, or add it to the list of out-of-turn replies we've received.
        if (recvd.is_reply()) {
            IPC_ASSERT(!mInterruptStack.empty(), "invalid Interrupt stack");

            // If this is not a reply the call we've initiated, add it to our
            // out-of-turn replies and keep polling for events.
            {
                const Message &outcall = mInterruptStack.top();

                // Note, In the parent, sequence numbers increase from 0, and
                // in the child, they decrease from 0.
                if ((mSide == ChildSide && recvd.seqno() > outcall.seqno()) ||
                    (mSide != ChildSide && recvd.seqno() < outcall.seqno()))
                {
                    mOutOfTurnReplies[recvd.seqno()] = Move(recvd);
                    continue;
                }

                IPC_ASSERT(recvd.is_reply_error() ||
                           (recvd.type() == (outcall.type() + 1) &&
                            recvd.seqno() == outcall.seqno()),
                           "somebody's misbehavin'", true);
            }

            // We received a reply to our most recent outstanding call. Pop
            // this frame and return the reply.
            mInterruptStack.pop();

            bool is_reply_error = recvd.is_reply_error();
            if (!is_reply_error) {
                *aReply = Move(recvd);
            }

            // If we have no more pending out calls waiting on replies, then
            // the reply queue should be empty.
            IPC_ASSERT(!mInterruptStack.empty() || mOutOfTurnReplies.empty(),
                       "still have pending replies with no pending out-calls",
                       true);

            return !is_reply_error;
        }

        // Dispatch an Interrupt in-call. Snapshot the current stack depth while we
        // own the monitor.
        size_t stackDepth = InterruptStackDepth();
        {
            MonitorAutoUnlock unlock(*mMonitor);

            CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
            DispatchInterruptMessage(recvd, stackDepth);
        }
        if (!Connected()) {
            ReportConnectionError("MessageChannel::DispatchInterruptMessage");
            return false;
        }
    }

    return true;
}

bool
MessageChannel::WaitForIncomingMessage()
{
#ifdef OS_WIN
    SyncStackFrame frame(this, true);
    NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
#endif

    { // Scope for lock
        MonitorAutoLock lock(*mMonitor);
        AutoEnterWaitForIncoming waitingForIncoming(*this);
        if (mChannelState != ChannelConnected) {
            return false;
        }
        if (!HasPendingEvents()) {
            return WaitForInterruptNotify();
        }
    }

    return OnMaybeDequeueOne();
}

bool
MessageChannel::HasPendingEvents()
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();
    return Connected() && !mPending.empty();
}

bool
MessageChannel::InterruptEventOccurred()
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();
    IPC_ASSERT(InterruptStackDepth() > 0, "not in wait loop");

    return (!Connected() ||
            !mPending.empty() ||
            (!mOutOfTurnReplies.empty() &&
             mOutOfTurnReplies.find(mInterruptStack.top().seqno()) !=
             mOutOfTurnReplies.end()));
}

bool
MessageChannel::ProcessPendingRequest(const Message &aUrgent)
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();

    // Note that it is possible we could have sent a sync message at
    // the same time the parent process sent an urgent message, and
    // therefore mPendingUrgentRequest is set *and* mRecvd is set as
    // well, because the link thread received both before the worker
    // thread woke up.
    //
    // In this case, we process the urgent message first, but we need
    // to save the reply.
    nsAutoPtr savedReply(mRecvd.forget());

    DispatchMessage(aUrgent);
    if (!Connected()) {
        ReportConnectionError("MessageChannel::ProcessPendingRequest");
        return false;
    }

    // In between having dispatched our reply to the parent process, and
    // re-acquiring the monitor, the parent process could have already
    // processed that reply and sent the reply to our sync message. If so,
    // our saved reply should be empty.
    IPC_ASSERT(!mRecvd || !savedReply, "unknown reply");
    if (!mRecvd)
        mRecvd = savedReply.forget();
    return true;
}

bool
MessageChannel::DequeueOne(Message *recvd)
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();

    if (!Connected()) {
        ReportConnectionError("OnMaybeDequeueOne");
        return false;
    }

    if (!mDeferred.empty())
        MaybeUndeferIncall();

    if (mPending.empty())
        return false;

    *recvd = Move(mPending.front());
    mPending.pop_front();
    return true;
}

bool
MessageChannel::OnMaybeDequeueOne()
{
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();

    Message recvd;

    MonitorAutoLock lock(*mMonitor);
    if (!DequeueOne(&recvd))
        return false;

    if (IsOnCxxStack() && recvd.is_interrupt() && recvd.is_reply()) {
        // We probably just received a reply in a nested loop for an
        // Interrupt call sent before entering that loop.
        mOutOfTurnReplies[recvd.seqno()] = Move(recvd);
        return false;
    }

    // We should not be in a transaction yet if we're not blocked.
    MOZ_ASSERT(mCurrentTransaction == 0);
    DispatchMessage(recvd);

    return true;
}

void
MessageChannel::DispatchMessage(const Message &aMsg)
{
    Maybe nojsapi;
    if (ScriptSettingsInitialized() && NS_IsMainThread())
        nojsapi.emplace();

    nsAutoPtr reply;

    {
        AutoEnterTransaction transaction(this, aMsg);

        int id = aMsg.transaction_id();
        MOZ_ASSERT_IF(aMsg.is_sync(), id == mCurrentTransaction);

        {
            MonitorAutoUnlock unlock(*mMonitor);
            CxxStackFrame frame(*this, IN_MESSAGE, &aMsg);

            if (aMsg.is_sync())
                DispatchSyncMessage(aMsg, *getter_Transfers(reply));
            else if (aMsg.is_interrupt())
                DispatchInterruptMessage(aMsg, 0);
            else
                DispatchAsyncMessage(aMsg);
        }

        if (mCurrentTransaction != id) {
            // The transaction has been canceled. Don't send a reply.
            reply = nullptr;
        }
    }

    if (reply && ChannelConnected == mChannelState) {
        mLink->SendMessage(reply.forget());
    }
}

void
MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply)
{
    AssertWorkerThread();

    int prio = aMsg.priority();

    // We don't want to run any code that might run a nested event loop here, so
    // we avoid running event handlers. Once we've sent the response to the
    // urgent message, it's okay to run event handlers again since the parent is
    // no longer blocked.
    MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread());
    MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL);

    MessageChannel* dummy;
    MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy;

    Result rv;
    if (mTimedOutMessageSeqno && mTimedOutMessagePriority >= prio) {
        // If the other side sends a message in response to one of our messages
        // that we've timed out, then we reply with an error.
        //
        // We do this because want to avoid a situation where we process an
        // incoming message from the child here while it simultaneously starts
        // processing our timed-out CPOW. It's very bad for both sides to
        // be processing sync messages concurrently.
        //
        // The only exception is if the incoming message has urgent priority and
        // our timed-out message had only high priority. In that case it's safe
        // to process the incoming message because we know that the child won't
        // process anything (the child will defer incoming messages when waiting
        // for a response to its urgent message).
        rv = MsgNotAllowed;
    } else {
        AutoSetValue blocked(blockingVar, this);
        AutoSetValue sync(mDispatchingSyncMessage, true);
        AutoSetValue prioSet(mDispatchingSyncMessagePriority, prio);
        rv = mListener->OnMessageReceived(aMsg, aReply);
    }

    if (!MaybeHandleError(rv, aMsg, "DispatchSyncMessage")) {
        aReply = new Message();
        aReply->set_sync();
        aReply->set_priority(aMsg.priority());
        aReply->set_reply();
        aReply->set_reply_error();
    }
    aReply->set_seqno(aMsg.seqno());
    aReply->set_transaction_id(aMsg.transaction_id());
}

void
MessageChannel::DispatchAsyncMessage(const Message& aMsg)
{
    AssertWorkerThread();
    MOZ_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync());

    if (aMsg.routing_id() == MSG_ROUTING_NONE) {
        NS_RUNTIMEABORT("unhandled special message!");
    }

    Result rv;
    {
        int prio = aMsg.priority();
        AutoSetValue async(mDispatchingAsyncMessage, true);
        AutoSetValue prioSet(mDispatchingAsyncMessagePriority, prio);
        rv = mListener->OnMessageReceived(aMsg);
    }
    MaybeHandleError(rv, aMsg, "DispatchAsyncMessage");
}

void
MessageChannel::DispatchInterruptMessage(const Message& aMsg, size_t stackDepth)
{
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();

    IPC_ASSERT(aMsg.is_interrupt() && !aMsg.is_reply(), "wrong message type");

    // Race detection: see the long comment near mRemoteStackDepthGuess in
    // MessageChannel.h. "Remote" stack depth means our side, and "local" means
    // the other side.
    if (aMsg.interrupt_remote_stack_depth_guess() != RemoteViewOfStackDepth(stackDepth)) {
        // Interrupt in-calls have raced. The winner, if there is one, gets to defer
        // processing of the other side's in-call.
        bool defer;
        const char* winner;
        const Message& parentMsg = (mSide == ChildSide) ? aMsg : mInterruptStack.top();
        const Message& childMsg = (mSide == ChildSide) ? mInterruptStack.top() : aMsg;
        switch (mListener->MediateInterruptRace(parentMsg, childMsg))
        {
          case RIPChildWins:
            winner = "child";
            defer = (mSide == ChildSide);
            break;
          case RIPParentWins:
            winner = "parent";
            defer = (mSide != ChildSide);
            break;
          case RIPError:
            NS_RUNTIMEABORT("NYI: 'Error' Interrupt race policy");
            return;
          default:
            NS_RUNTIMEABORT("not reached");
            return;
        }

        if (LoggingEnabled()) {
            printf_stderr("  (%s: %s won, so we're%sdeferring)\n",
                          (mSide == ChildSide) ? "child" : "parent",
                          winner,
                          defer ? " " : " not ");
        }

        if (defer) {
            // We now know the other side's stack has one more frame
            // than we thought.
            ++mRemoteStackDepthGuess; // decremented in MaybeProcessDeferred()
            mDeferred.push(aMsg);
            return;
        }

        // We "lost" and need to process the other side's in-call. Don't need
        // to fix up the mRemoteStackDepthGuess here, because we're just about
        // to increment it in DispatchCall(), which will make it correct again.
    }

#ifdef OS_WIN
    SyncStackFrame frame(this, true);
#endif

    nsAutoPtr reply;

    ++mRemoteStackDepthGuess;
    Result rv = mListener->OnCallReceived(aMsg, *getter_Transfers(reply));
    --mRemoteStackDepthGuess;

    if (!MaybeHandleError(rv, aMsg, "DispatchInterruptMessage")) {
        reply = new Message();
        reply->set_interrupt();
        reply->set_reply();
        reply->set_reply_error();
    }
    reply->set_seqno(aMsg.seqno());

    MonitorAutoLock lock(*mMonitor);
    if (ChannelConnected == mChannelState) {
        mLink->SendMessage(reply.forget());
    }
}

void
MessageChannel::MaybeUndeferIncall()
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();

    if (mDeferred.empty())
        return;

    size_t stackDepth = InterruptStackDepth();

    // the other side can only *under*-estimate our actual stack depth
    IPC_ASSERT(mDeferred.top().interrupt_remote_stack_depth_guess() <= stackDepth,
               "fatal logic error");

    // maybe time to process this message
    Message call = mDeferred.top();
    mDeferred.pop();

    // fix up fudge factor we added to account for race
    IPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
    --mRemoteStackDepthGuess;

    MOZ_ASSERT(call.priority() == IPC::Message::PRIORITY_NORMAL);
    mPending.push_back(call);
}

void
MessageChannel::FlushPendingInterruptQueue()
{
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();

    {
        MonitorAutoLock lock(*mMonitor);

        if (mDeferred.empty()) {
            if (mPending.empty())
                return;

            const Message& last = mPending.back();
            if (!last.is_interrupt() || last.is_reply())
                return;
        }
    }

    while (OnMaybeDequeueOne());
}

void
MessageChannel::ExitedCxxStack()
{
    mListener->OnExitedCxxStack();
    if (mSawInterruptOutMsg) {
        MonitorAutoLock lock(*mMonitor);
        // see long comment in OnMaybeDequeueOne()
        EnqueuePendingMessages();
        mSawInterruptOutMsg = false;
    }
}

void
MessageChannel::EnqueuePendingMessages()
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();

    MaybeUndeferIncall();

    for (size_t i = 0; i < mDeferred.size(); ++i) {
        mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
    }

    // XXX performance tuning knob: could process all or k pending
    // messages here, rather than enqueuing for later processing

    for (size_t i = 0; i < mPending.size(); ++i) {
        mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
    }
}

static inline bool
IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout)
{
    return (aTimeout != PR_INTERVAL_NO_TIMEOUT) &&
           (aTimeout <= (PR_IntervalNow() - aStart));
}

bool
MessageChannel::WaitResponse(bool aWaitTimedOut)
{
    if (aWaitTimedOut) {
        if (mInTimeoutSecondHalf) {
            // We've really timed out this time.
            return false;
        }
        // Try a second time.
        mInTimeoutSecondHalf = true;
    } else {
        mInTimeoutSecondHalf = false;
    }
    return true;
}

#ifndef OS_WIN
bool
MessageChannel::WaitForSyncNotify(bool /* aHandleWindowsMessages */)
{
    PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ?
                             PR_INTERVAL_NO_TIMEOUT :
                             PR_MillisecondsToInterval(mTimeoutMs);
    // XXX could optimize away this syscall for "no timeout" case if desired
    PRIntervalTime waitStart = PR_IntervalNow();

    mMonitor->Wait(timeout);

    // If the timeout didn't expire, we know we received an event. The
    // converse is not true.
    return WaitResponse(IsTimeoutExpired(waitStart, timeout));
}

bool
MessageChannel::WaitForInterruptNotify()
{
    return WaitForSyncNotify(true);
}

void
MessageChannel::NotifyWorkerThread()
{
    mMonitor->Notify();
}
#endif

bool
MessageChannel::ShouldContinueFromTimeout()
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();

    bool cont;
    {
        MonitorAutoUnlock unlock(*mMonitor);
        cont = mListener->OnReplyTimeout();
    }

    static enum { UNKNOWN, NOT_DEBUGGING, DEBUGGING } sDebuggingChildren = UNKNOWN;

    if (sDebuggingChildren == UNKNOWN) {
        sDebuggingChildren = getenv("MOZ_DEBUG_CHILD_PROCESS") ? DEBUGGING : NOT_DEBUGGING;
    }
    if (sDebuggingChildren == DEBUGGING) {
        return true;
    }

    return cont;
}

void
MessageChannel::SetReplyTimeoutMs(int32_t aTimeoutMs)
{
    // Set channel timeout value. Since this is broken up into
    // two period, the minimum timeout value is 2ms.
    AssertWorkerThread();
    mTimeoutMs = (aTimeoutMs <= 0)
                 ? kNoTimeout
                 : (int32_t)ceil((double)aTimeoutMs / 2.0);
}

void
MessageChannel::OnChannelConnected(int32_t peer_id)
{
    MOZ_ASSERT(!mPeerPidSet);
    mPeerPidSet = true;
    mPeerPid = peer_id;
    mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mOnChannelConnectedTask));
}

void
MessageChannel::DispatchOnChannelConnected()
{
    AssertWorkerThread();
    MOZ_ASSERT(mPeerPidSet);
    if (mListener)
        mListener->OnChannelConnected(mPeerPid);
}

void
MessageChannel::ReportMessageRouteError(const char* channelName) const
{
    PrintErrorMessage(mSide, channelName, "Need a route");
    mListener->OnProcessingError(MsgRouteError, "MsgRouteError");
}

void
MessageChannel::ReportConnectionError(const char* aChannelName, Message* aMsg) const
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();

    const char* errorMsg = nullptr;
    switch (mChannelState) {
      case ChannelClosed:
        errorMsg = "Closed channel: cannot send/recv";
        break;
      case ChannelOpening:
        errorMsg = "Opening channel: not yet ready for send/recv";
        break;
      case ChannelTimeout:
        errorMsg = "Channel timeout: cannot send/recv";
        break;
      case ChannelClosing:
        errorMsg = "Channel closing: too late to send/recv, messages will be lost";
        break;
      case ChannelError:
        errorMsg = "Channel error: cannot send/recv";
        break;

      default:
        NS_RUNTIMEABORT("unreached");
    }

    if (aMsg) {
        char reason[512];
        PR_snprintf(reason, sizeof(reason),
                    "(msgtype=0x%lX,name=%s) %s",
                    aMsg->type(), aMsg->name(), errorMsg);

        PrintErrorMessage(mSide, aChannelName, reason);
    } else {
        PrintErrorMessage(mSide, aChannelName, errorMsg);
    }

    MonitorAutoUnlock unlock(*mMonitor);
    mListener->OnProcessingError(MsgDropped, errorMsg);
}

bool
MessageChannel::MaybeHandleError(Result code, const Message& aMsg, const char* channelName)
{
    if (MsgProcessed == code)
        return true;

    const char* errorMsg = nullptr;
    switch (code) {
      case MsgNotKnown:
        errorMsg = "Unknown message: not processed";
        break;
      case MsgNotAllowed:
        errorMsg = "Message not allowed: cannot be sent/recvd in this state";
        break;
      case MsgPayloadError:
        errorMsg = "Payload error: message could not be deserialized";
        break;
      case MsgProcessingError:
        errorMsg = "Processing error: message was deserialized, but the handler returned false (indicating failure)";
        break;
      case MsgRouteError:
        errorMsg = "Route error: message sent to unknown actor ID";
        break;
      case MsgValueError:
        errorMsg = "Value error: message was deserialized, but contained an illegal value";
        break;

    default:
        NS_RUNTIMEABORT("unknown Result code");
        return false;
    }

    char reason[512];
    PR_snprintf(reason, sizeof(reason),
                "(msgtype=0x%lX,name=%s) %s",
                aMsg.type(), aMsg.name(), errorMsg);

    PrintErrorMessage(mSide, channelName, reason);

    mListener->OnProcessingError(code, reason);

    return false;
}

void
MessageChannel::OnChannelErrorFromLink()
{
    AssertLinkThread();
    mMonitor->AssertCurrentThreadOwns();

    if (InterruptStackDepth() > 0)
        NotifyWorkerThread();

    if (AwaitingSyncReply() || AwaitingIncomingMessage())
        NotifyWorkerThread();

    if (ChannelClosing != mChannelState) {
        if (mAbortOnError) {
            NS_RUNTIMEABORT("Aborting on channel error.");
        }
        mChannelState = ChannelError;
        mMonitor->Notify();
    }

    PostErrorNotifyTask();
}

void
MessageChannel::NotifyMaybeChannelError()
{
    mMonitor->AssertNotCurrentThreadOwns();

    // TODO sort out Close() on this side racing with Close() on the other side
    if (ChannelClosing == mChannelState) {
        // the channel closed, but we received a "Goodbye" message warning us
        // about it. no worries
        mChannelState = ChannelClosed;
        NotifyChannelClosed();
        return;
    }

    // Oops, error!  Let the listener know about it.
    mChannelState = ChannelError;
    mListener->OnChannelError();
    Clear();
}

void
MessageChannel::OnNotifyMaybeChannelError()
{
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();

    mChannelErrorTask = nullptr;

    // OnChannelError holds mMonitor when it posts this task and this
    // task cannot be allowed to run until OnChannelError has
    // exited. We enforce that order by grabbing the mutex here which
    // should only continue once OnChannelError has completed.
    {
        MonitorAutoLock lock(*mMonitor);
        // nothing to do here
    }

    if (IsOnCxxStack()) {
        mChannelErrorTask =
            NewRunnableMethod(this, &MessageChannel::OnNotifyMaybeChannelError);
        // 10 ms delay is completely arbitrary
        mWorkerLoop->PostDelayedTask(FROM_HERE, mChannelErrorTask, 10);
        return;
    }

    NotifyMaybeChannelError();
}

void
MessageChannel::PostErrorNotifyTask()
{
    mMonitor->AssertCurrentThreadOwns();

    if (mChannelErrorTask)
        return;

    // This must be the last code that runs on this thread!
    mChannelErrorTask =
        NewRunnableMethod(this, &MessageChannel::OnNotifyMaybeChannelError);
    mWorkerLoop->PostTask(FROM_HERE, mChannelErrorTask);
}

// Special async message.
class GoodbyeMessage : public IPC::Message
{
public:
    GoodbyeMessage() :
        IPC::Message(MSG_ROUTING_NONE, GOODBYE_MESSAGE_TYPE, PRIORITY_NORMAL)
    {
    }
    static bool Read(const Message* msg) {
        return true;
    }
    void Log(const std::string& aPrefix, FILE* aOutf) const {
        fputs("(special `Goodbye' message)", aOutf);
    }
};

void
MessageChannel::SynchronouslyClose()
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();
    mLink->SendClose();
    while (ChannelClosed != mChannelState)
        mMonitor->Wait();
}

void
MessageChannel::CloseWithError()
{
    AssertWorkerThread();

    MonitorAutoLock lock(*mMonitor);
    if (ChannelConnected != mChannelState) {
        return;
    }
    SynchronouslyClose();
    mChannelState = ChannelError;
    PostErrorNotifyTask();
}

void
MessageChannel::CloseWithTimeout()
{
    AssertWorkerThread();

    MonitorAutoLock lock(*mMonitor);
    if (ChannelConnected != mChannelState) {
        return;
    }
    SynchronouslyClose();
    mChannelState = ChannelTimeout;
}

void
MessageChannel::BlockScripts()
{
    MOZ_ASSERT(NS_IsMainThread());
    mBlockScripts = true;
}

void
MessageChannel::Close()
{
    AssertWorkerThread();

    {
        MonitorAutoLock lock(*mMonitor);

        if (ChannelError == mChannelState || ChannelTimeout == mChannelState) {
            // See bug 538586: if the listener gets deleted while the
            // IO thread's NotifyChannelError event is still enqueued
            // and subsequently deletes us, then the error event will
            // also be deleted and the listener will never be notified
            // of the channel error.
            if (mListener) {
                MonitorAutoUnlock unlock(*mMonitor);
                NotifyMaybeChannelError();
            }
            return;
        }

        if (ChannelOpening == mChannelState) {
            // SynchronouslyClose() waits for an ack from the other side, so
            // the opening sequence should complete before this returns.
            SynchronouslyClose();
            mChannelState = ChannelError;
            NotifyMaybeChannelError();
            return;
        }

        if (ChannelConnected != mChannelState) {
            // XXX be strict about this until there's a compelling reason
            // to relax
            NS_RUNTIMEABORT("Close() called on closed channel!");
        }

        // notify the other side that we're about to close our socket
        mLink->SendMessage(new GoodbyeMessage());
        SynchronouslyClose();
    }

    NotifyChannelClosed();
}

void
MessageChannel::NotifyChannelClosed()
{
    mMonitor->AssertNotCurrentThreadOwns();

    if (ChannelClosed != mChannelState)
        NS_RUNTIMEABORT("channel should have been closed!");

    // OK, the IO thread just closed the channel normally.  Let the
    // listener know about it.
    mListener->OnChannelClose();

    Clear();
}

void
MessageChannel::DebugAbort(const char* file, int line, const char* cond,
                           const char* why,
                           bool reply) const
{
    printf_stderr("###!!! [MessageChannel][%s][%s:%d] "
                  "Assertion (%s) failed.  %s %s\n",
                  mSide == ChildSide ? "Child" : "Parent",
                  file, line, cond,
                  why,
                  reply ? "(reply)" : "");
    // technically we need the mutex for this, but we're dying anyway
    DumpInterruptStack("  ");
    printf_stderr("  remote Interrupt stack guess: %" PRIuSIZE "\n",
                  mRemoteStackDepthGuess);
    printf_stderr("  deferred stack size: %" PRIuSIZE "\n",
                  mDeferred.size());
    printf_stderr("  out-of-turn Interrupt replies stack size: %" PRIuSIZE "\n",
                  mOutOfTurnReplies.size());
    printf_stderr("  Pending queue size: %" PRIuSIZE ", front to back:\n",
                  mPending.size());

    MessageQueue pending = mPending;
    while (!pending.empty()) {
        printf_stderr("    [ %s%s ]\n",
                      pending.front().is_interrupt() ? "intr" :
                      (pending.front().is_sync() ? "sync" : "async"),
                      pending.front().is_reply() ? "reply" : "");
        pending.pop_front();
    }

    NS_RUNTIMEABORT(why);
}

void
MessageChannel::DumpInterruptStack(const char* const pfx) const
{
    NS_WARN_IF_FALSE(MessageLoop::current() != mWorkerLoop,
                     "The worker thread had better be paused in a debugger!");

    printf_stderr("%sMessageChannel 'backtrace':\n", pfx);

    // print a python-style backtrace, first frame to last
    for (uint32_t i = 0; i < mCxxStackFrames.length(); ++i) {
        int32_t id;
        const char* dir;
        const char* sems;
        const char* name;
        mCxxStackFrames[i].Describe(&id, &dir, &sems, &name);

        printf_stderr("%s[(%u) %s %s %s(actor=%d) ]\n", pfx,
                      i, dir, sems, name, id);
    }
}

int32_t
MessageChannel::GetTopmostMessageRoutingId() const
{
    MOZ_ASSERT(MessageLoop::current() == mWorkerLoop);
    if (mCxxStackFrames.empty()) {
        return MSG_ROUTING_NONE;
    }
    const InterruptFrame& frame = mCxxStackFrames.back();
    return frame.GetRoutingId();
}

void
MessageChannel::CancelCurrentTransactionInternal()
{
    // When we cancel a transaction, we need to behave as if there's no longer
    // any IPC on the stack. Anything we were dispatching or sending will get
    // canceled. Consequently, we have to update the state variables below.
    //
    // We also need to ensure that when any IPC functions on the stack return,
    // they don't reset these values using an RAII class like AutoSetValue. To
    // avoid that, these RAII classes check if the variable they set has been
    // tampered with (by us). If so, they don't reset the variable to the old
    // value.

    MOZ_ASSERT(mCurrentTransaction);
    mCurrentTransaction = 0;

    mAwaitingSyncReply = false;
    mAwaitingSyncReplyPriority = 0;

    // We could also zero out mDispatchingSyncMessage here. However, that would
    // cause a race because mDispatchingSyncMessage is a worker-thread-only
    // field and we can be called on the I/O thread. Luckily, we can check to
    // see if mCurrentTransaction is 0 before examining DispatchSyncMessage.
}

void
MessageChannel::CancelCurrentTransaction()
{
    MonitorAutoLock lock(*mMonitor);
    if (mCurrentTransaction) {
        CancelCurrentTransactionInternal();
        mLink->SendMessage(new CancelMessage());
    }
}

void
CancelCPOWs()
{
    if (gParentProcessBlocker) {
        mozilla::Telemetry::Accumulate(mozilla::Telemetry::IPC_TRANSACTION_CANCEL, true);
        gParentProcessBlocker->CancelCurrentTransaction();
    }
}

} // namespace ipc
} // namespace mozilla

 

 

你可能感兴趣的:(ff,os)