面對網頁擷圖、轉存 PDF、爬網頁、自動測試等需求,Headless Chrome 是十分可靠的免費解決方案。但由於 Chrome 屬桌面程式,實務應用上我習慣將其寫成排程程式或 Windows Service 以便掌控執行身分、執行個體數量,比直接由 IIS/IIS Express 呼叫穩定不易出錯。(延伸閱讀:使用 ASP.NET Core 快速打造 Windows Service - 以 Headless Chrome 網頁抓圖為例)

不過,幾個月前接到使用者報案,某個使用 Headless Chrome 抓圖的排程一夕崩壞,經過調查與對照,查出是 Chrome 從 72 升級到 73 版造成。幸運找到測試環境,重現「呼叫 Headless Chrome 的背景程序(排程、Windows Service)在 Chrome 72 版時可正常運作,一升級 73 後馬上壞掉」取得鐵證,在 Stackoverflow 發問 也得到網友證實。當時找到的鋸箭解法是將排程改用桌面登入者身分執行,並確保有使用者登入,勉強讓排程繼續運作。

最近另一個專案也遇到網頁轉存 PDF 需求,但這回得走 Windows Service,鋸箭法無效,只能出來面對。

重啟調查有了重大發現,原來這是 Chrome 73 的 Bug (Issue 942023),3 月被提報,4 月初已修正好提交。想將此一發現補充在 Stackoverflow 提問,我想找出 Chrome 確實的修正版號,沒想到這個簡單的念頭,竟耗掉我大半個週末,噗!

摸索過程學到不少東西,在此記錄備忘。

Chromiumn 的 Source 位於 https://chromium.googlesource.com/chromium/src/,在 Github 有一份 Mirror

Issue 942023 討論提到兩個 Commit:

  1. Commit 200abd62a22a433cc155d6718c2718693654aa61 2019/4/4 22:57 by kylechar
    作者修正當 Chrome 由自動程序或服務啟動時,因 Thread 型別導致程式凍結無反應的問題
  2. Commit 51314b0234d3ec9c730e7934d96d449850e864a6 2019/4/9 13:27 by kylechar
    上述修正通過 Merge Review,由 master 合併到 branch-heads/3729

但是由上述線索無法得知 Chrome 是從哪一版加入這個修正,只能繼續調查。

Chromium 有四種發行頻道(Release Channel):

  1. Stable Channel
    經完整測試,擁有 Chrome Team 品質保證,大約每兩週一次小改版,每六週一次主要改版
  2. Beta Chennel 可預覽新功能,較 Stable Channel 提早一個月推出,約每週一次小改版,六週一次主要改版
  3. Dev Channel
    適合想優先嘗試最新功能的玩家,每週更新一到兩次,有測試但 Bug 稍多
  4. Canary Channel
    每日更新,不經測試,一建置好就釋出

Chrome 版本發行資訊可在 Chrome Release查到,上面有各平台 Chrome (Android、iOS、Desktop)的更新公告,限定 Label: Desktop Update縮小範圍,4/9 後的第一次穩定版本更新(Stable Channel Update)為 2019/4/23 釋出的Chrome 74,公告附有修改清單,從 73.0.3683.103 升到 74.0.3729.108 版的差異項目包含 51314b0234d3ec9c730e7934d96d449850e864a6 Commit,證實 Chrome 在 74 版發行時已修正這個問題:

如此即可得到我要的答案。但最近剛學 Git,就想順便見識 Chromium 這等規模的大型開源專案怎麼處理 Commit、Branch,沒想到一頭栽進去莫名又搞了好幾個小時。

我先下載了總容量高達 13GB 的 Chromium Git 儲存庫,內含超過一千兩百萬個物件! (而且提交修改的頻率很高,一天幾十次)

用 Sourcetree 看 Chromium 的分支線圖長這樣:(Sourcetree 操作起這麼大的儲存庫也十分吃力,每個動作都要花點時間等待載入完成)

Chromium Team 不喜歡將新功能放在 feature 分支發展,而是選擇將功能提交到 master 但透過旗標先停用(這篇 Release process 有提到不用 feature 分支的理由,但本機開發時一樣是取 orgin/master 開分支修 Bug 或加功能參考),故線圖上不存在 feature 分支,master 分支外還有三個並行的主版號分支(如上圖的75.0.3770, 76.0.3809, 77.0.3832)。 新功能或修改經 Code Review 後會合併到入主版號分支,每次編譯有 Bot 程式會自動加上 Tag。

每個主版分支維持至少一天一次編譯,Canary 版為每晚更新,但以 74.0.3729 為例,蠻常出現一天編譯兩次的狀況。(註:Chromium 版號規則) 而 Chrome 75 版於 6/4 釋出,6/3 之後 74 版便未再更新。

git 指令補充:--simplify-by-decoration 參數 限定被 Branch 或 Tag 參考的 Commit、--pretty 格式參數 %ai %d 顯示簽入時間與參考名稱

最後順手做了 Git 練習:

  1. 找出 kylechar 在 4/4 之後的 Commit git log --author=kylechar --pretty="format:%ai %s" --after="2019-04-04T00:00:00Z"
    > git log --author=kylechar --pretty="format:%ai %s" --after="2019-04-04T00:00:00Z"
    2019-06-14 18:45:59 +0000 oopd: Update handling fatal context error.
    2019-06-14 17:21:31 +0000 Fix histograms in DirectLayerTreeFrameSink.
    2019-06-13 22:50:15 +0000 Fix Windows resize jitter with SkiaRenderer.
    2019-06-12 16:46:24 +0000 Don't try to exit already exiting GPU process.
    2019-06-11 18:14:59 +0000 Fix CopyOutputResult StructTraits.
    2019-06-10 20:03:04 +0000 Disable leaking viz_unittests on LSAN.
    2019-06-07 18:50:40 +0000 Cleanup chrome://gpu feature list.
    2019-06-06 16:23:39 +0000 Fix direct composition with SkiaRenderer.
    2019-06-06 15:39:53 +0000 Update blocking scope allowance for TaskGraphRunners.
    2019-06-06 14:49:34 +0000 Add note to Windows cross build instructions.
    2019-06-06 13:00:19 +0000 Remove ImageTransportSurfaceDelegate functions.
    2019-06-05 14:13:07 +0000 Add logging to CopyOutputResult deserialization.
    2019-06-04 14:57:35 +0000 Remove extra tests for SurfaceHitTest path.
    2019-06-03 16:17:43 +0000 ozone: Cleanup callback types.
    2019-05-29 21:07:32 +0000 Fix aura::Window::CreateLayerTreeFrameSink() DCHECK.
    2019-05-29 16:54:46 +0000 Rename [Compositor]OverlayCandidateValidatorAndroid.
    2019-05-28 17:15:30 +0000 Merge [Compositor]OverlayCandidateValidator classes.
    2019-05-28 00:58:30 +0000 Improve smooth scaling for reflected surfaces.
    2019-05-21 18:35:31 +0000 base: Cleanup callback types (part 5).
    2019-05-17 17:12:48 +0000 Add webgl_conformance_vulkan_passthrough_tests suppressions.
    2019-05-17 15:35:33 +0000 Update webg2l conformence test expectations.
    2019-05-16 17:08:18 +0000 Update webgl2_conformance_expectations.
    2019-05-16 15:22:57 +0000 Revert "Adding FastHash() function"
    2019-05-15 23:52:00 +0000 Mark webgl2 tests flaky for Windows Intel bots.
    2019-05-15 17:22:42 +0000 base: Cleanup callback types (part 4).
    2019-05-15 13:39:11 +0000 base: Cleanup callback types (part 3).
    2019-05-14 14:26:03 +0000 Revert "Roll src/third_party/pdfium 726ece1b5340..2169a778183b (1 commits)"
    2019-05-13 15:27:59 +0000 oopd: Delete win/mac code for VizDisplayCompositor disabled.
    2019-05-10 14:08:08 +0000 Don't call gfx::ToNearestRect() on non-integer RectF.
    2019-05-08 14:35:54 +0000 Small code cleanup for compositor_frame_fuzzer.
    2019-05-07 21:08:08 +0000 exo: Make Texture::Buffer a ContextLostObserver.
    2019-05-07 15:10:02 +0000 exo: Handle DidLoseLayerTreeFrameSink() for OOP-D.
    2019-05-06 22:48:57 +0000 Remove GPU.EstablishGpuChannelDuration.* UMA
    2019-05-02 15:53:36 +0000 Move Software[BrowserCompositor]OutputSurfaceTest.
    2019-05-01 22:25:52 +0000 Don't check VizDisplayCompositor feature on win/mac.
    2019-05-01 14:37:34 +0000 oopd: Handle GPU compositing failure on Chrome OS.
    2019-04-30 15:38:26 +0000 Remove kEnableSurfaceSynchronization switch.
    2019-04-29 19:01:40 +0000 Don't check VizDisplayCompositor feature on desktop.
    2019-04-26 20:15:02 +0000 Remove AdaptCallbackForRepeating() in ImportantFileWriter.
    2019-04-26 18:23:12 +0000 Add mojo interface for vsync parameter updates.
    2019-04-26 17:02:50 +0000 Use SharedImageInterface in GLOutputSurfaceOffscreen.
    2019-04-24 14:51:20 +0000 base: Cleanup callback types (part 2).
    2019-04-16 21:19:47 +0000 Change how vsync parameter updates are plumbed.
    2019-04-04 22:57:13 +0000 Make VizCompositorThread TYPE_DEFAULT on Windows.
    
  2. 找出訊息出現 VizCompositorThread 字眼的 Commit
    > git log --pretty="format:%ai %s" --grep="VizCompositorThread"
    2019-06-06 08:58:59 +0000 [ozone/wayland] Fix broken software rendering path.
    2019-04-04 22:57:13 +0000 Make VizCompositorThread TYPE_DEFAULT on Windows.
    2019-01-16 22:31:28 +0000 ozone: scenic: Use IO message loop for VizCompositorThread
    2018-08-16 21:46:23 +0000 Use VizCompositorThreadRunner in VizMainImpl.
    2018-08-03 00:35:30 +0000 Reland "Add in-process VizCompositorThread for software compositing."
    2018-08-02 18:38:14 +0000 Revert "Add in-process VizCompositorThread for software compositing."
    2018-08-02 17:49:25 +0000 Add in-process VizCompositorThread for software compositing.
    2018-03-09 22:53:00 +0000 Roll src/third_party/catapult/ e490e96cd..21ff400bb (3 commits)
    
  3. 顯示指定的 Commit 內容
    > git show 200abd62
    commit 200abd62a22a433cc155d6718c2718693654aa61
    Author: kylechar <kylechar@chromium.org>
    Date:   Thu Apr 4 22:57:13 2019 +0000
    
        Make VizCompositorThread TYPE_DEFAULT on Windows.
    
        When Chrome is launched by a service in a console session, which seems
        to how Chrome is launched from some automation frameworks, creating a
        message only window for MessagePumpForUI fails in the GPU process. As a
        result VizCompositorThread fails to run any tasks and nothing is ever
        drawn, see https://crbug.com/942023.
    
        The display compositor thread was originally made TYPE_UI on Windows in
        https://crrev.com/c/1025954. This was to allow using a child HWND
        created in the GPU process for software composited output. That code was
        deleted in https://crrev.com/c/1450399 so the thread shouldn't need to
        be TYPE_UI anymore.
    
        Bug: 942023
        Change-Id: I2a7dbf46a3a772b5ab1a9a20367d3e7f08116cbc
        Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1549763
        Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
        Commit-Queue: kylechar <kylechar@chromium.org>
        Cr-Commit-Position: refs/heads/master@{#647967}
    
    diff --git a/components/viz/service/main/viz_compositor_thread_runner.cc b/components/viz/service/main/viz_compositor_thread_runner.cc
    index 076546e6b966..bc76bac5f127 100644
    --- a/components/viz/service/main/viz_compositor_thread_runner.cc
    +++ b/components/viz/service/main/viz_compositor_thread_runner.cc
    @@ -49,10 +49,7 @@ std::unique_ptr<VizCompositorThreadType> CreateAndStartCompositorThread() {
       auto thread = std::make_unique<base::Thread>(kThreadName);
    
       base::Thread::Options thread_options;
    -#if defined(OS_WIN)
    -  // Windows needs a UI message loop for child HWND.
    -  thread_options.message_loop_type = base::MessageLoop::TYPE_UI;
    -#elif defined(USE_OZONE)
    +#if defined(USE_OZONE)
       // We may need a non-default message loop type for the platform surface.
       thread_options.message_loop_type =
           ui::OzonePlatform::GetInstance()->GetMessageLoopTypeForGpu();
    
    以及
    > git show 51314b0
    commit 51314b0234d3ec9c730e7934d96d449850e864a6
    Author: kylechar <kylechar@chromium.org>
    Date:   Tue Apr 9 13:27:32 2019 +0000
    
        Make VizCompositorThread TYPE_DEFAULT on Windows.
    
        When Chrome is launched by a service in a console session, which seems
        to how Chrome is launched from some automation frameworks, creating a
        message only window for MessagePumpForUI fails in the GPU process. As a
        result VizCompositorThread fails to run any tasks and nothing is ever
        drawn, see https://crbug.com/942023.
    
        The display compositor thread was originally made TYPE_UI on Windows in
        https://crrev.com/c/1025954. This was to allow using a child HWND
        created in the GPU process for software composited output. That code was
        deleted in https://crrev.com/c/1450399 so the thread shouldn't need to
        be TYPE_UI anymore.
    
        Bug: 942023
        Change-Id: I2a7dbf46a3a772b5ab1a9a20367d3e7f08116cbc
        Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1549763
        Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
        Commit-Queue: kylechar <kylechar@chromium.org>
        Cr-Original-Commit-Position: refs/heads/master@{#647967}(cherry picked from commit 200abd62a22a433cc155d6718c2718693654aa61)
        Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1559912
        Reviewed-by: kylechar <kylechar@chromium.org>
        Cr-Commit-Position: refs/branch-heads/3729@{#739}
        Cr-Branched-From: d4a8972e30b604f090aeda5dfff68386ae656267-refs/heads/master@{#638880}
    
    diff --git a/components/viz/service/main/viz_compositor_thread_runner.cc b/components/viz/service/main/viz_compositor_thread_runner.cc
    index 9585baf7845f..6e0a544f2695 100644
    --- a/components/viz/service/main/viz_compositor_thread_runner.cc
    +++ b/components/viz/service/main/viz_compositor_thread_runner.cc
    @@ -49,10 +49,7 @@ std::unique_ptr<VizCompositorThreadType> CreateAndStartCompositorThread() {
       auto thread = std::make_unique<base::Thread>(kThreadName);
    
       base::Thread::Options thread_options;
    -#if defined(OS_WIN)
    -  // Windows needs a UI message loop for child HWND.
    -  thread_options.message_loop_type = base::MessageLoop::TYPE_UI;
    -#elif defined(USE_OZONE)
    +#if defined(USE_OZONE)
       // We may need a non-default message loop type for the platform surface.
       thread_options.message_loop_type =
           ui::OzonePlatform::GetInstance()->GetMessageLoopTypeForGpu();
    
    

來個 Git 觀念題,200abd62a22a433cc155d6718c2718693654aa61 與 51314b0234d3ec9c730e7934d96d449850e864a6 這兩筆 Commit 個別查 SHA1 都查得到,但 git log 搜索關鍵字 VizCompositorThread 時卻只看得到 200abd6,為什麼?

原因是 200abd6 在 master 分支,51314b0 位於 branch-heads/3729 分支,在 master 分支查詢 git log 只會看到 200abd6。由於 Clone 複製的儲存庫並不存在 branch-heads/3279 分支,無法直接切換分支,但要看到 51314b0 不難,我們有 74.0.3729.xxx Tag,git checkout 74.0.3729.108,再下 git log,51314b0 就現身囉~

This article give a brief of Chromium release channels and source branching strategy.


Comments

Be the first to post a comment

Post a comment