ArkUI のスレッドとウォッチドッグ メカニズム

I.はじめに

この記事では、主に ArkUI に関連するスレッドとウォッチドッグ メカニズムを分析します。

2. ArkUI のスレッド

アビリティを適用して初めてインターフェースを作成するプロセスは、大まかに次のようになります。

説明します:

• AceContainer は、フロント エンド、タスク エグゼキュータ、リソース マネージャ、レンダリング パイプライン、ビューなどで構成されるコンテナ クラスです。ライフサイクル ドッキング、機能スケジューリング インターフェイス、UI レンダリングのさまざまな機能を提供します。

• アビリティは、実際には FA モデルの AceAbility であり、AceContainer コンテナ クラスの管理インターフェイスと一致します。AceAbility のライフサイクル関数 AceAbility::OnStart(const Want& want) で AceContainer インスタンスを作成します。

• Stage モデルの場合、UIContentImpl::CommonInitialize() 関数で AceContainer インスタンスを作成します。AceContainer は、コンストラクターでタスク エグゼキューターを作成して、ArkUI 関連のタスクを実行します。

void AceContainer::InitializeTask()
{
    auto flutterTaskExecutor = Referenced::MakeRefPtr<FlutterTaskExecutor>();
    flutterTaskExecutor->InitPlatformThread(useCurrentEventRunner_);
    taskExecutor_ = flutterTaskExecutor;
    // No need to create JS Thread for DECLARATIVE_JS
    if (type_ == FrontendType::DECLARATIVE_JS) {
        GetSettings().useUIAsJSThread = true;
    } else {
        flutterTaskExecutor->InitJsThread();
    }
}

タスクには以下のようにいくつかの種類があり、各種類のタスク (バックグラウンド タスクを除く) は fml::TaskRunner によって実行されます。TaskRunner コードは、サードパーティ ライブラリ third_party\flutter\engine\flutter\common\task_runners.h にあります。実装の原則は、EventRunner および EventHandler の場合と同様です。

enum class TaskType : uint32_t {
        PLATFORM = 0,
        UI,
        IO,
        GPU,
        JS,
        BACKGROUND,
        UNKNOWN,
    };

FlutterTaskExecutor クラス図は次のとおりです。

説明します:

• タスク エグゼキュータを使用して、非同期 (PostTask) および同期 (PostSyncTask) タスクを実行できます。

• 非同期タスク: 現在のスレッドをブロックすることなく、指定されたタイプのスレッドにタスクをスローして処理します。

• 同期タスク: 処理のために指定されたタイプのスレッドにタスクをスローし、タスクが実行されるまで現在のスレッドをブロックして、現在のスレッドを続行します。

• たとえば、タッチ イベントの処理は、非同期タスクの形式で処理するために UI スレッドにスローされます。

 auto&& touchEventCallback = [context = pipelineContext_, id = instanceId_](
                                    const TouchEvent& event, const std::function<void()>& markProcess) {
        ContainerScope scope(id);
        context->GetTaskExecutor()->PostTask(
            [context, event, markProcess]() {
                context->OnTouchEvent(event);
                CHECK_NULL_VOID_NOLOG(markProcess);
                markProcess();
            },
            TaskExecutor::TaskType::UI);
    };

3. さまざまなタイプの TaskRunner を初期化する方法は?

1. platformRunner_

InitPlatformThread 関数で初期化します。

void FlutterTaskExecutor::InitPlatformThread(bool useCurrentEventRunner)
{
#ifdef OHOS_STANDARD_SYSTEM
    platformRunner_ = flutter::PlatformTaskRunner::CurrentTaskRunner(useCurrentEventRunner);
#else
    fml::MessageLoop::EnsureInitializedForCurrentThread();
    platformRunner_ = fml::MessageLoop::GetCurrent().GetTaskRunner();
#endif

    FillTaskTypeTable(TaskType::PLATFORM);
}

標準の OHOS の場合、platformRunner_ は実際には

flutter::PlatformTaskRunner::CurrentTaskRunner(useCurrentEventRunner)

具体的な実装を見てください:

fml::RefPtr<fml::TaskRunner> PlatformTaskRunner::CurrentTaskRunner(bool useCurrentEventRunner)
{
    return PlatformTaskRunnerAdapter::CurrentTaskRunner(useCurrentEventRunner);
}
fml::RefPtr<fml::TaskRunner> PlatformTaskRunnerAdapter::CurrentTaskRunner(bool useCurrentEventRunner)
{
    if (useCurrentEventRunner) {
        return fml::MakeRefCounted<PlatformTaskRunnerAdapter>(useCurrentEventRunner);
    }
    if (taskRunner_) {
        return taskRunner_;
    }
    taskRunner_ = fml::MakeRefCounted<PlatformTaskRunnerAdapter>(useCurrentEventRunner);
    return taskRunner_;
}

説明します:

platformRunner の実際のタイプは PlatformTaskRunnerAdapter です。

PlatformTaskRunnerAdapter は fml::TaskRunner を継承し、仮想 void PostTask(fml::closure task) などのインターフェイス関数を実装します。実際、レイヤーのカプセル化は、EventRunner および EventHandler メカニズムに基づいて行われます。コード内の useCurrentEventRunner の実パラメータは false です。これは、platformRunner が実際にタスクをメイン スレッドにスローして実行することを意味します。(MainEventRunner に対応するスレッドがメインスレッドで、MainEventRunner の初期化は Ability フレームワークの MainThread::Start() 関数で行われます)

PlatformTaskRunnerAdapter::PlatformTaskRunnerAdapter(bool useCurrentEventRunner)
    : fml::TaskRunner(nullptr)
{
    if (useCurrentEventRunner) {
        eventRunner_ = OHOS::AppExecFwk::EventRunner::Current();
    } else {
        eventRunner_ = OHOS::AppExecFwk::EventRunner::GetMainEventRunner();
    }
    eventHandler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(eventRunner_);
}

void PlatformTaskRunnerAdapter::PostTask(fml::closure task)
{
    eventHandler_->PostTask(std::move(task));
}

2.uiRunner、ioRunner、gpuRunner_

これら 3 種類の TaskRunner 初期化は、FlutterTaskExecutor::InitOtherThreads 関数にあります。

void FlutterTaskExecutor::InitOtherThreads(const flutter::TaskRunners& taskRunners)
{
    uiRunner_ = taskRunners.GetUITaskRunner();
    ioRunner_ = taskRunners.GetIOTaskRunner();
#ifdef NG_BUILD
    gpuRunner_ = taskRunners.GetRasterTaskRunner();
#else
    gpuRunner_ = taskRunners.GetGPUTaskRunner();
#endif

    //...此处省略若干行
}

FlutterTaskExecutor::InitOtherThreads 関数のパラメータ taskRunners はどこから来たのですか?

一部の構成項目は FlutterAceView::CreateView() 関数で初期化され、次に flutter::OhosShellHolder オブジェクトが作成されます。

FlutterAceView* FlutterAceView::CreateView(int32_t instanceId, bool useCurrentEventRunner, bool usePlatformThread)
{
    FlutterAceView* aceSurface = new Platform::FlutterAceView(instanceId);
    if (aceSurface != nullptr) {
        aceSurface->IncRefCount();
    }
    flutter::Settings settings;
    settings.instanceId = instanceId;
    settings.platform = flutter::AcePlatform::ACE_PLATFORM_OHOS;
#ifndef GPU_DISABLED
    settings.enable_software_rendering = false;
#else
    settings.enable_software_rendering = true;
#endif
#ifdef ENABLE_ROSEN_BACKEND
    settings.use_system_render_thread = SystemProperties::GetRosenBackendEnabled();
#endif
    settings.platform_as_ui_thread = usePlatformThread;
    settings.use_current_event_runner = useCurrentEventRunner;
    // ...此处省略若干行
    auto shell_holder = std::make_unique<flutter::OhosShellHolder>(settings, false);
    if (aceSurface != nullptr) {
        aceSurface->SetShellHolder(std::move(shell_holder));
    }
    return aceSurface;
}

OhosShellHolder コンストラクターは、渡されたパラメーターに従って flutter::TaskRunners を作成します。

OhosShellHolder::OhosShellHolder(
    flutter::Settings settings,
    bool is_background_view)
    : settings_(std::move(settings))
{
  // ...此处省略若干行
  // The current thread will be used as the platform thread. Ensure that the
  // message loop is initialized.
  fml::MessageLoop::EnsureInitializedForCurrentThread();
  fml::RefPtr<fml::TaskRunner> gpu_runner;
  fml::RefPtr<fml::TaskRunner> ui_runner;
  fml::RefPtr<fml::TaskRunner> io_runner;
  fml::RefPtr<fml::TaskRunner> platform_runner =
    PlatformTaskRunnerAdapter::CurrentTaskRunner(settings_.use_current_event_runner);
  if (is_background_view) {
    auto single_task_runner = thread_host_.ui_thread->GetTaskRunner();
    gpu_runner = single_task_runner;
    ui_runner = single_task_runner;
    io_runner = single_task_runner;
  } else {
    if (settings_.platform_as_ui_thread) {
      ui_runner = platform_runner;
    } else {
      ui_runner = thread_host_.ui_thread->GetTaskRunner();
    }
    if (!settings_.use_system_render_thread) {
      gpu_runner = thread_host_.gpu_thread->GetTaskRunner();
    } else {
      gpu_runner = ui_runner;
    }
    if (settings_.use_io_thread) {
      io_runner = thread_host_.io_thread->GetTaskRunner();
    } else {
      io_runner = ui_runner;
    }
  }
  flutter::TaskRunners task_runners(thread_label,     // label
                                    platform_runner,  // platform
                                    gpu_runner,       // gpu
                                    ui_runner,        // ui
                                    io_runner         // io
  );

注: 現在 OHOS では、構成パラメーターは次のとおりです。

上記のコード セグメントと比較すると、実際の gpu_runner、ui_runner、および io_runner は同じであり、タスクはすべて UI スレッドで実行されます。また、Stage モデルの場合、ui_runner と platform_runner は同じなので、Stage モデルの場合、TaskType::UI、TaskType::IO、TaskType::GPU、TaskType::PLATFORM タイプのタスクは、実際には のメイン スレッドによって実行されます。 .

3.jsRunner_

初期化は FlutterTaskExecutor::InitJsThread(bool newThread) 関数で行われます。

void FlutterTaskExecutor::InitJsThread(bool newThread)
{
    if (newThread) {
        jsThread_ = std::make_unique<fml::Thread>(GenJsThreadName());
        jsRunner_ = jsThread_->GetTaskRunner();
    } else {
        jsRunner_ = uiRunner_;
    }

    PostTaskToTaskRunner(
        jsRunner_, [weak = AceType::WeakClaim(this)] { FillTaskTypeTable(weak, TaskType::JS); }, 0);
}

説明: 宣言型フロント エンドの場合、newThread パラメーターは false ですが、JS フロント エンドの場合は true です。したがって、宣言型フロントエンド JS スレッドは実際には UI スレッドであり、JS フロントエンドでは、JS 関連のタスクを処理するために独立した JS スレッドが設定されます。

4. TaskType::BACKGROUND タイプのタスクを実行する方法は?

タイプ TaskType::BACKGROUND のタスクは、シングルトンの BackgroundTaskExecutor によって実行されます。時間のかかるバックグラウンド操作を処理するために、8 つのスレッドのスレッド プールが BackgroundTaskExecutor で維持されます。スレッド名は「ace.bg」で始まります。たとえば、RosenFontLoader が Web フォントをロードする場合、ダウンロード操作はバックグラウンド タスク スレッドで実行されます。

void RosenFontLoader::LoadFromNetwork(const OHOS::Ace::RefPtr<OHOS::Ace::PipelineBase>& context)
{
    auto weakContext = AceType::WeakClaim(AceType::RawPtr(context));
    context->GetTaskExecutor()->PostTask(
        [weak = AceType::WeakClaim(this), weakContext] {
            auto fontLoader = weak.Upgrade();
            auto context = weakContext.Upgrade();
            if (!fontLoader || !context) {
                return;
            }
            std::vector<uint8_t> fontData;
            if (!DownloadManager::GetInstance().Download(fontLoader->familySrc_, fontData) || fontData.empty()) {
                return;
            }
            //...此处省略若干行
        },
        TaskExecutor::TaskType::BACKGROUND);
}

要約すると、ArkUI では、インターフェイスを持つ各アビリティに対して AceContainer が作成され、アビリティ ArkUI に関連するタスクを処理するために各 AceContainer に FlutterTaskExecutor が作成されます。異なるモデルに従って、ArkUI によって作成されるスレッドは異なります。

• Stage モデル アプリケーションの場合、ui スレッドはメイン スレッドを再利用します。Stage モデル アプリケーションは現在、宣言型フロントエンドであるため、js スレッドが ui スレッドを再利用します。したがって、ArkUI は、名前が「ace.bg」で始まる 8 つの追加のバックグラウンド タスク スレッドを作成するだけで済みます。

• FA モデルの適用では、8 つのバックグラウンド タスク スレッドに加えて、名前が「.ui」で終わるスレッドが、アビリティの数に応じていくつか作成されます。JS フロントエンドの場合、「jsThread-」で始まる名前のスレッドがいくつか作成されます。

4.ArkUIのウォッチドッグ

AceEngine はシングルトンであり、グローバルに一意です。WatchDog インスタンスは、AceEngine のコンストラクターで作成されます。FA モデルの適用のために、AceContainer::AttachView() 関数呼び出し

AceEngine::Get().RegisterToWatchDog(instanceId, taskExecutor_,

GetSettings().useUIAsJSThread);

保持している FlutterTaskExecutor をウォッチドッグに登録します。

ウォッチドッグは、FlutterTaskExecutor の UI スレッドと JS スレッドのみを保護します。UI スレッドと JS スレッドは実際には多重化のメイン スレッドであるため、Stage モデルのアプリケーションを ArkUI で保護する必要はありません。アビリティ フレームワークには、メイン スレッドを保護するためのウォッチドッグがあります。スレッド内に 3 秒以上のタスク処理がある場合、RawEventType::WARNING に対応するシステム イベントが hiview プラグイン プラットフォームに報告され、タスク処理が 5 秒を超える場合、RawEventType::FREEZE に対応するシステム イベントが報告されます。 hiview プラグイン プラットフォームに報告され、hiview プラグイン プラットフォーム appfreeze のダンプ ファイルが生成されます。

メインスレッドや UI スレッドがスタックして appfreeze が発生するのを防ぐため、アプリケーション開発を行う際は、アビリティのライフサイクル関数やコントロール クリック イベントなどのコールバック関数で時間のかかる操作を実行しないでください。

おすすめ

転載: blog.csdn.net/OpenHarmony_dev/article/details/129547691