Android UpdateEngineモジュール解析(3) アップグレードトリガーと動作メカニズムの紹介

序文

UpdateEngine モジュールのコンパイルと起動プロセスを以前に分析し、UpdateEngine モジュールについて予備的な理解をしました。次に、アップグレード機能から開始して、UpdateEngine の更新プロセスを分析します。分析を開始します。多くの手順があります。 UpdateEngine の更新プロセスでは、各ステップがアクションによって制御されます。したがって、最初に UpdateEngine モジュールのアクション メカニズムを説明し、アップグレードのトリガー方法と実装プロセスについて説明します。

前: Android UpdateEngine モジュール分析 (2) UpdateEngine サービスの開始
次: Android UpdateEngine モジュール分析 (4) UpdateEngine アップグレード ロジック

文章

UpdateEngine の更新をトリガーするには 2 つの方法があります。

1 つ目は、コマンド ライン クライアントの形式でトリガーする方法です。これは、コマンド ラインの update_engine_client ツールによってトリガーされます。

2 つ目は、Android が提供するネイティブ インターフェイスを使用してトリガーする方法で、 Aidlインターフェイスと UpdateEngine間の通信に基づいてプロセスに応じてトリガーされます。

1. update_engine_client コマンドライン

update_engine_client コマンド ラインを使用してアップグレードをトリガーする場合は、まずSOCの zip アップグレード パッケージを解凍し、次の形式のファイルを取得する必要があります。

├── META-INF
│ └── com
│ └── android
│ ├── metadata
│ └── otacert
├── payload.bin
└── payload_properties.txt

update_engine_client コマンドの形式は次のとおりです。

update_engine_client --payload=file://payload.bin路径 --update --headers="文件hash、文件大小、metadata hash、metadata大小"

次に、 cmd コマンド ラインにadbシェルを入力します。アップグレード コマンドを入力します。

update_engine_client --payload=file:///storage/5F49-FB9D/socupdate/payload.bin --update --headers="FILE_HASH=PLo9cSeCeECAhKHlk06drRFHCyd1BGHE/fliEd0F3uQ=
FILE_SIZE=2447066254
METADATA_HASH=H+gFeOLUWil1LyX4VOJIhGvHHv+MrFu1RBdxXzhorHQ=
METADATA_SIZE=179338"

アップグレードが完了したら、cat proc/cmdline を使用して、アップグレード前後の AB パーティションの切り替えを表示し、アップグレードが成功したかどうかを判断できます。以下に示すように、「androidboot.slot_suffix」は現在実行中のパーティションを表します。

:/ # cat proc/cmdline
root=/dev/ram0 rootfstype=ramfs highres=1 earlycon loglevel=4 console=ttyS0,115200n8 fbcon=map:1 androidboot.mode=normal androidboot.debuggable=1 androidboot.dm_verity=disable androidboot.vdsp=disable init=/init init=/init androidboot.console=ttyS0 consoleblank=0 androidboot.hardware=x9m_ref androidboot.boot_devices=soc/34180000.sdhci,soc/341a0000.sdhci firmware_class.path=/vendor/firmware hardware.platform=x9m_ref androidboot.wificountrycode=CN buildvariant=userdebug androidboot.slot_suffix=_b androidboot.storage_type=emmc androidboot.verifiedbootstate=orange androidboot.force_normal_boot=1

2. Androidインターフェース

Android ソース コードでは、Google はローカル USB ディスク上の SOC デモをアップグレードするための SystemUpdater という名前の APK を提供しています。これは、update_engine インターフェイスの呼び出しプロセスを記述するデモ アプリケーションとして理解できます。次に、このアプリケーションから始めて、インターフェイス呼び出しプロセスから開始し、プロセスに従ってネイティブ インターフェイスのアップグレードを使用するプロセスを分析します。

2.1 SystemUpdaterを適用する

2.1.1 SystemUpdater の概要

SystemUpdater アプリケーションのコード ディレクトリは次のとおりです: android/packages/apps/Car/SystemUpdater

アプリケーション起動コマンド: adb shell am start -n com.android.car.systemupdater.SystemUpdaterActivity

主な機能は次のとおりです。

U ディスク内のアップグレード ファイルを読み取り、ユーザーはターゲットのアップグレード ファイルをクリックします

UpdateEngine アップグレードの進行状況と結果のコールバックを登録し、UpdateEngine アップグレード インターフェイスを呼び出してアップグレード パラメータを渡してアップグレードをトリガーします

アップグレード後にマシンを再起動するように powermanager に通知します

コード ファイルは次のとおりです。

├── DeviceListFragment.java
├── SystemUpdaterActivity.java
├── UpdateLayoutFragment.java
├── UpdateParser.java
└── UpFragment.java

2.2.2 SystemUpdater キーの処理

以下は、SystemUpdater 呼び出しのタイミング図です。

ここに画像の説明を挿入

アップグレードには 2 つの手順が必要で、1 つ目はアップグレードの進行状況と結果のコールバックを登録すること、2 つ目はアップグレードをトリガーすることです。

以下は、アップグレードに関連する SystemUpdater のコードの一部です。


/** Show the install now button. */
    private void showInstallNow(UpdateParser.ParsedUpdate update) {
        mContentTitle.setText(R.string.install_ready);
        mContentInfo.append(getString(R.string.update_file_name, mUpdateFile.getName()));
        mContentInfo.append(System.getProperty("line.separator"));
        mContentInfo.append(getString(R.string.update_file_size));
        mContentInfo.append(Formatter.formatFileSize(getContext(), mUpdateFile.length()));
        mContentDetails.setText(null);
        mSystemUpdateToolbarAction.setOnClickListener(v -> installUpdate(update));  // 准备升级
        mSystemUpdateToolbarAction.setText(R.string.install_now);
        mSystemUpdateToolbarAction.setVisibility(View.VISIBLE);
    }
    
/** Attempt to install the update that is copied to the device. */
    private void installUpdate(UpdateParser.ParsedUpdate parsedUpdate) {
        showInstallationInProgress();  // 注册升级信息回调并显示升级进度
        mUpdateEngine.applyPayload(
                parsedUpdate.mUrl, parsedUpdate.mOffset, parsedUpdate.mSize, parsedUpdate.mProps);  // 调用升级接口触发升级
    }
	
/** Set the layout to show installation progress. */
    private void showInstallationInProgress() {
        mInstallationInProgress = true;
        mProgressBar.setIndeterminate(false);
        mProgressBar.setVisibility(View.VISIBLE);
        mProgressBar.setMax(PERCENT_MAX);
        mSystemUpdateToolbarAction.setVisibility(View.GONE);
        showStatus(R.string.install_in_progress);

        mUpdateEngine.bind(mCarUpdateEngineCallback, new Handler(getContext().getMainLooper()));  // 绑定升级信息回调
    }
    
/** Handles events from the UpdateEngine. */
    // 升级信息回调实现
    public class CarUpdateEngineCallback extends UpdateEngineCallback {

        // 升级状态、进度回调
        @Override
        public void onStatusUpdate(int status, float percent) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, String.format("onStatusUpdate %d, Percent %.2f", status, percent));
            }
            switch (status) {
                case UpdateEngine.UpdateStatusConstants.UPDATED_NEED_REBOOT:
                    rebootNow();
                    break;
                case UpdateEngine.UpdateStatusConstants.DOWNLOADING:
                    mProgressBar.setProgress((int) (percent * 100));
                    break;
                default:
                    // noop
            }
        }

        // 升级结果回调
        @Override
        public void onPayloadApplicationComplete(int errorCode) {
            Log.w(TAG, String.format("onPayloadApplicationComplete %d", errorCode));
            mInstallationInProgress = false;
            showStatus(errorCode == UpdateEngine.ErrorCodeConstants.SUCCESS
                    ? R.string.install_success
                    : R.string.install_failed);
            mProgressBar.setVisibility(View.GONE);
            mSystemUpdateToolbarAction.setVisibility(View.GONE);
        }
    }

    /** Build a notification to show the installation status. */
    private static Notification createNotification(Context context, @StringRes int contents) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(context, SystemUpdaterActivity.class));
        intent.putExtra(EXTRA_RESUME_UPDATE, true);
        PendingIntent pendingIntent =
                PendingIntent.getActivity(
                        context,
                        /* requestCode= */ 0,
                        intent,
                        PendingIntent.FLAG_UPDATE_CURRENT);

        return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
                .setVisibility(Notification.VISIBILITY_PUBLIC)
                .setContentTitle(context.getString(contents))
                .setSmallIcon(R.drawable.ic_system_update_alt_black_48dp)
                .setContentIntent(pendingIntent)
                .setShowWhen(false)
                .setOngoing(true)
                .setAutoCancel(false)
                .build();
    }

2.2 UpdateEngine のアーキテクチャ

以下の図はUpdateEngineのアーキテクチャ図です。

ここに画像の説明を挿入

UpdateEngine モジュール構造の説明:
(1) フレームワーク Java モジュール
システムは、アプリケーションにアップグレード呼び出しインターフェイスを提供する Framework.jar パッケージをコンパイルして生成し、基礎となる HAL 層と対話してコールバックします。

(2) AIDLインターフェースは
上位層とHAL層のインターフェース定義を記述し、プロセス間の通信を行う

(3) HAL 層モジュールupdate_engine ビジネス処理
のメインモジュールであり、AIDL インターフェイスを実装してサービスを提供します。SOC アップグレード プロセスは、ActionProcessor 管理によって順次かつ段階的に実行される 5 つのアクションによって実現されます。

次の図は、フレームワーク層の UpdateEngine.java クラス図であり、主にアプリケーションに提供されるインターフェイスを説明します。

ここに画像の説明を挿入

次の図は、フレームワーク層の UpdateEngineCallback.java クラス図であり、主にアプリケーションが実装する必要があるインターフェイスを説明しています。

ここに画像の説明を挿入

次の表は、UpdateEngine の AIDL インターフェイスを定義します。

update_engine AIDL インターフェース定義 機能説明
void applyPayload (String url、in long payload_offset、in long payload_size、in String[] headerKeyValuePairs); applyPayload インターフェイスを呼び出し、アップグレード パラメータを渡し、アップグレードを開始します [url: アップグレード パッケージ パス Payload_offset: update.zip 内のペイロード オフセット Payload_size: ペイロード ファイル サイズ headerKeyValuePairs: メタデータ内のデータ]
ブール値バインド (IUpdateEngineCallback コールバック) コールバックをバインドすると、下層はこのコールバックを通じてアップグレード ステータス、アップグレードの進行結果、その他の情報を上位層に通知します [コールバック: IUpdateEngineCallback を実装するオブジェクト]
ブール値のアンバインド (IUpdateEngineCallback コールバック) アンバインド コールバック。上記のバインド コールバックに対応します。アンバインド [コールバック: IUpdateEngineCallback を実装するオブジェクト]
ボイドサスペンド() アップグレードを一時停止します。上位層はこのインターフェイスを通じてアップグレード プロセスを一時停止できます。
void 再開() アップグレードを再開します。上位層は、このインターフェイスを介して一時停止スイッチからアップグレード ステータスを復元できます。
無効キャンセル() アップグレードをキャンセルします。上位層はこのインターフェイスを通じてアップグレードをキャンセルできます。
void リセットステータス() アップグレードステータスをリセットします。上位層は、このインターフェイスを通じてアップグレード ステータスをリセットします。
ブール値 verifyPayloadApplicable (文字列メタデータファイル名内) このメタデータ データをこのデバイスに適用できるかどうかを確認します [メタデータ パス]

次の表は、UpdateEngine コールバック インターフェイスを定義します。

update_engine コールバック Aidl インターフェイス定義 機能説明
void onStatusUpdate (int status_code、float パーセンテージ) アップグレードステータスのコールバック、進行状況のコールバック
void onPayloadApplicationComplete (int error_code) アップグレード結果のコールバック

UpdateEngine モジュール関数のフローチャート:

ここに画像の説明を挿入

UpdateEngine の登録、アップグレード、コールバック プロセスのシーケンス図は次のとおりです。

ここに画像の説明を挿入

2.3 System UpdateEngine のアップグレード プロセス

全体的な概要: UpdateEngine のアップグレード プロセスに関しては、上記の 2 つの主要なインターフェイス、bind と applyPayload から開始して、アップグレード プロセス applyPayload とアップグレード コールバック プロセスの binding について説明する予定です。

2.3.1 アップグレードプロセス

2.3.1.1 動作メカニズム

アップグレード プロセスの説明を始める前に、UpdateEngine がアップグレード ステップを管理する方法の概要を説明し、まずアップグレード ステップ全体を理解する必要があります。

2.3.1.1.1 アクション

UpdateEngine のアップグレード プロセスでは、更新プロセス全体が論理的に 5 つのステップに分割され、各ステップはアクション (update_boot_flags_action、install_plan_action、download_action、filesystem_verifier_action、および postinstall_runner_action) によって表されます。

アクション 意味 機能の簡単な説明
update_boot_flags_action update_boot_flags_action.h 一部のフラグ変数の初期化を完了
インストール計画アクション install_plan.h InstallPlan 構造体変数を構築し、OutputPipe を関連付ける
ダウンロードアクション ダウンロード_アクション.h http_fetcher をビルドしてアップグレード データのダウンロードを完了すると、DeltaPerformer の Writer_ オブジェクトがデータの分析と更新に使用されます。
ファイルシステム検証者アクション filesystem_verifier_action.h アップグレードする必要があるパーティションの HASH 値を 1 つずつ確認します
postinstall_runner_action postinstall_runner_action.h アップグレードされたパーティションでポストインストール スクリプトを実行し、アップグレードが成功した後、パーティションを起動可能なアクティブ状態に設定します。

Action の定義に関しては、AbstractAction と Action の 2 つのクラスが関係します。定義はすべて /android/system/update_engine/common/action.h のパスの下にあります。以下は 2 つのクラスのクラス図です。

AbstractAction クラス図:

ここに画像の説明を挿入

アクションクラス図:

ここに画像の説明を挿入

AbstractAction クラスは、Action 基本クラスとして理解できます。その中で定義された仮想関数、各特定のアクションは、このクラスの仮想関数メソッドをオーバーライドし、開始、一時停止、アクションのさまざまな段階の論理関数を定義します。シーン関数のロジックを完成させる、resume、stop、Action クラスは AbstractAction クラスを継承し、ActionPipe の機能を導入し、Action の入出力オブジェクトを定義します。

次に、UpdateEngine で定義された Action には、関数ロジックと ActionPipe 入力および出力オブジェクトという上記の 2 つのクラスの機能が必要です。UpdateEngine で定義された Action は InstallPlanAction から継承され、InstallPlanAction は Action から継承されます。

文件:android/system/update_engine/common/action.h

// It is handy to have a non-templated base class of all Actions.
// 拥有所有 Actions 的非模板基类

class AbstractAction {
 public:
  AbstractAction() : processor_(nullptr) {}
  virtual ~AbstractAction() = default;

  // Begin performing the action. Since this code is asynchronous, when this
  // method returns, it means only that the action has started, not necessarily
  // completed. However, it's acceptable for this method to perform the
  // action synchronously; Action authors should understand the implications
  // of synchronously performing, though, because this is a single-threaded
  // app, the entire process will be blocked while the action performs.
  //
  // When the action is complete, it must call
  // ActionProcessor::ActionComplete(this); to notify the processor that it's
  // done.
  /*
   * 开始执行操作。
   * 此代码是异步的,当方法返回时,仅以为这该动作已经开始,并不一定完成。
   * 不过方法可以同步执行操作,需要了解同步执行的含义,因为这是一个单线程应用程序,所以动作执行时会阻塞整个过程。
   * 操作完成后,必须调用 ActionProcessor::ActionComplete(this);通知处理器已完成。
   */
  virtual void PerformAction() = 0;

  // Called on ActionProcess::ActionComplete() by ActionProcessor.
  // 执行 ActionProcess::ActionComplete()
  virtual void ActionCompleted(ErrorCode code) {}

  // Called by the ActionProcessor to tell this Action which processor
  // it belongs to.
  // 由 ActionProcessor 调用以说明这个 Action 数据哪个 processor
  void SetProcessor(ActionProcessor* processor) {
    if (processor)
      CHECK(!processor_);
    else
      CHECK(processor_);
    processor_ = processor;
  }

  // Returns true iff the action is the current action of its ActionProcessor.
  // 当这个 action 是 ActionPorcessor 当前正在运行的 action 时返回 true。
  bool IsRunning() const {
    if (!processor_)
      return false;
    return processor_->current_action() == this;
  }

  // Called on asynchronous actions if canceled. Actions may implement if
  // there's any cleanup to do. There is no need to call
  // ActionProcessor::ActionComplete() because the processor knows this
  // action is terminating.
  // Only the ActionProcessor should call this.
  // 如果要执行任何清理操作,可以实施此操作。
  virtual void TerminateProcessing() {}

  // Called on asynchronous actions if the processing is suspended and resumed,
  // respectively. These methods are called by the ActionProcessor and should
  // not be explicitly called.
  // The action may still call ActionCompleted() once the action is completed
  // while the processing is suspended, for example if suspend/resume is not
  // implemented for the given action.
  // 暂停当前 action 的执行。
  virtual void SuspendAction() {}
  // 恢复当前暂停的 action 为执行。
  virtual void ResumeAction() {}

  // These methods are useful for debugging. TODO(adlr): consider using
  // std::type_info for this?
  // Type() returns a string of the Action type. I.e., for DownloadAction,
  // Type() would return "DownloadAction".
  virtual std::string Type() const = 0;

 protected:
  // A weak pointer to the processor that owns this Action.
  // 一个指向拥有这些 action 操作的 ActionProcessor 对象的弱指针。
  ActionProcessor* processor_;
};

// Action 类继承自 AbstractAction,是对 Action 输入对象、输出对象定义的延申。
class Action : public AbstractAction {
 public:
  ~Action() override {}

  // Attaches an input pipe to this Action. This is optional; an Action
  // doesn't need to have an input pipe. The input pipe must be of the type
  // of object that this class expects.
  // This is generally called by ActionPipe::Bond()
  /*
   * 将输入管道对象附加到此动作,此动作是可选的,第一个 Action 不需要输入管道。
   * 输入管道必须为该类期望的对象,通常由 ActionPipe::Bond() 调用。
   */
  void set_in_pipe(
      // this type is a fancy way of saying: a shared_ptr to an
      // ActionPipe<InputObjectType>.
      const std::shared_ptr<
          ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>&
          in_pipe) {
    in_pipe_ = in_pipe;
  }

  // Attaches an output pipe to this Action. This is optional; an Action
  // doesn't need to have an output pipe. The output pipe must be of the type
  // of object that this class expects.
  // This is generally called by ActionPipe::Bond()
  /*
   * 将输出管道附加到此操作。这是可选的,最后一个 Action 不需要输出管道。
   * 输出管道必须是此类所需要的对象类型。通常由 ActionPipe::Bond() 调用。
   */
  void set_out_pipe(
      // this type is a fancy way of saying: a shared_ptr to an
      // ActionPipe<OutputObjectType>.
      const std::shared_ptr<
          ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>&
          out_pipe) {
    out_pipe_ = out_pipe;
  }

  // Returns true iff there is an associated input pipe. If there's an input
  // pipe, there's an input object, but it may have been constructed with the
  // default ctor if the previous action didn't call SetOutputObject().
  /*
   * 如果存在关联的输入管道,则返回 true。
   * 如果存在输入管道,有一个输入对象,但是之前没有调用 SetOutputObject() 方法,那么对象有可能是默认构造函数创建的。
   */
  bool HasInputObject() const { return in_pipe_.get(); }

  // returns a const reference to the object in the input pipe.
  // 返回输入管道中对象的 const 引用。
  const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
      const {
    CHECK(HasInputObject());
    return in_pipe_->contents();
  }

  // Returns true iff there's an output pipe.
  // 如果有输出管道,则返回 true。
  bool HasOutputPipe() const { return out_pipe_.get(); }
  
  // Copies the object passed into the output pipe. It will be accessible to
  // the next Action via that action's input pipe (which is the same as this
  // Action's output pipe).
  // 复制传递到输出管道中的对象。下一个操作可以通过该操作输入管道访问此操作。
  // 也就是说 上一个Action 的输出管道对象 就是 下一个Action 的输入管道对象。
  void SetOutputObject(
      const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
    CHECK(HasOutputPipe());
    out_pipe_->set_contents(out_obj);
  }

  // Returns a reference to the object sitting in the output pipe.
  // 返回输出管道中对象的 const 引用。
  const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
    CHECK(HasOutputPipe());
    return out_pipe_->contents();
  }

 protected:
  // We use a shared_ptr to the pipe. shared_ptr objects destroy what they
  // point to when the last such shared_ptr object dies. We consider the
  // Actions on either end of a pipe to "own" the pipe. When the last Action
  // of the two dies, the ActionPipe will die, too.
  /*
   * 定义两个管道 输入管道 in_pipe_ 和 输出管道 out_pipe_。
   * 管道对象使用 shared_ptr 修饰,shared_ptr 对象会在最后一个这样的 shared_ptr 对象销毁同时销毁指向的对象。
   * 我们将管道两端的操作视为拥有管道。当两者的最后一个动作结束销毁时,管道也会销毁。
   * 
   * shared_ptr:
   * shared_ptr 的主要功能是管理动态创建的对象的销毁。
   * 它的基本原理就是记录对象被引用的次数,当引用次数为0的时候,也就是最后一个指向某对象的 共享指针析构 的时候,共享指针的析构函数就把 指向的内存区域 释放掉
   */
  std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>
      in_pipe_;
  std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>
      out_pipe_;
};

2.3.1.1.2 アクションプロセッサ

ActionはUpdateEngineのアップグレード手順を表すため、Actionを制御・管理する一連の仕組みが必要であり、ActionProcessorはエンキュー、開始、一時停止、再開、停止、状態判定、Action取得、動作終了ロジックなどの処理を制御・管理します。

ActionProcessorは「android/system/update_engine/common/action_processor.h」に定義されています。

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

ここに画像の説明を挿入

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

ここに画像の説明を挿入

文件:android/system/update_engine/common/action_processor.h

// ActionProcessor 类

class ActionProcessor {
 public:
  ActionProcessor() = default;

  virtual ~ActionProcessor();

  // Starts processing the first Action in the queue. If there's a delegate,
  // when all processing is complete, ProcessingDone() will be called on the
  // delegate.
  // 开始处理队列中的第一个 Action 动作。
  virtual void StartProcessing();

  // Aborts processing. If an Action is running, it will have
  // TerminateProcessing() called on it. The Action that was running and all the
  // remaining actions will be lost and must be re-enqueued if this Processor is
  // to use it.
  /*
   * 中止处理。
   * 如果某个 Action 正在运行,它将调用 TerminateProcessing(),如果此处理器要使用它,则正在运行的动作以及所有其他剩余动作将丢失,必须重新排队。
   */
  void StopProcessing();

  // Suspend the processing. If an Action is running, it will have the
  // SuspendProcessing() called on it, and it should suspend operations until
  // ResumeProcessing() is called on this class to continue. While suspended,
  // no new actions will be started. Calling SuspendProcessing while the
  // processing is suspended or not running this method performs no action.
  /*
   * 暂停处理。
   * 如果某个 Action 正在运行,它将调用 SuspendProcessing(),并且它应该暂停操作,直到在此类上调用 ResumeProcessing() 以继续。
   * 挂起期间,不会启动任何新操作,在处理挂起或未运行此方法时调用挂起处理不执行任何操作。
   */
  void SuspendProcessing();

  // Resume the suspended processing. If the ActionProcessor is not suspended
  // or not running in the first place this method performs no action.
  // 恢复挂起的处理。如果操作处理器未挂起或未首先运行,则此方法不执行任何操作。
  void ResumeProcessing();

  // Returns true iff the processing was started but not yet completed nor
  // stopped.
  // 定义一个方法用于判断当前 Action 的运行状态,运行或者暂停
  bool IsRunning() const;

  // Adds another Action to the end of the queue.
  // 将 Action 操作放入队列中
  virtual void EnqueueAction(std::unique_ptr<AbstractAction> action);
  
  // Sets/gets the current delegate. Set to null to remove a delegate.
  /*
   * 设置一个代理委托对象 ActionProcessorDelegate。
   * ActionProcessorDelegate 在下面定义,此类的作用是用于控制整体的 Action 操作的状态交互的。
   */
  ActionProcessorDelegate* delegate() const { return delegate_; }
  void set_delegate(ActionProcessorDelegate* delegate) { delegate_ = delegate; }

  // Returns a pointer to the current Action that's processing.
  // 返回当前正在运行的 Action 对象。
  AbstractAction* current_action() const { return current_action_.get(); }

  // Called by an action to notify processor that it's done. Caller passes self.
  // But this call deletes the action if there no other object has a reference
  // to it, so in that case, the caller should not try to access any of its
  // member variables after this call.
  // 当 Action 完成后通知 ActionProcessor 已完成。
  void ActionComplete(AbstractAction* actionptr, ErrorCode code);

 private:
  FRIEND_TEST(ActionProcessorTest, ChainActionsTest);

  // Continue processing actions (if any) after the last action terminated with
  // the passed error code. If there are no more actions to process, the
  // processing will terminate.
  // 当 Action 执行结束后调用,判断是执行队列中下一个 Action 还是结束整个过程。当 Action 因传递的错误码而终止后继续处理操作。
  void StartNextActionOrFinish(ErrorCode code);

  // Actions that have not yet begun processing, in the order in which
  // they'll be processed.
  // Action 队列
  std::deque<std::unique_ptr<AbstractAction>> actions_;

  // A pointer to the currently processing Action, if any.
  // 一个指向当前正在运行的 Action 指针。
  std::unique_ptr<AbstractAction> current_action_;

  // The ErrorCode reported by an action that was suspended but finished while
  // being suspended. This error code is stored here to be reported back to the
  // delegate once the processor is resumed.
  // 当调用 suspend 暂停 Action 过程中出现的 错误码 会存放在此处,以便于处理器恢复后报告给委托对象。
  ErrorCode suspended_error_code_{ErrorCode::kSuccess};

  // Whether the action processor is or should be suspended.
  // 定义一个标志位,判断是否未 暂停状态。
  bool suspended_{false};

  // A pointer to the delegate, or null if none.
  // 定义委托对象的指针。
  ActionProcessorDelegate* delegate_{nullptr};

  DISALLOW_COPY_AND_ASSIGN(ActionProcessor);
};

// ActionProcessorDelegate 类

// A delegate object can be used to be notified of events that happen
// in an ActionProcessor. An instance of this class can be passed to an
// ActionProcessor to register itself.
/*
 * ActionProcessorDelegate 委托对象可用于通知操作处理器中发生的事件。
 * 可以将此类的示例传递给 ActionProcessor 以注册自身。
 * 这个委托类,在 ActionProcessor 中进行注册,这样用委托调用 ActionProcessor 的方法,这样可以调用到 processor 的方法,也可以定义一些与外部交互的方法
 * 例如,Action 完成或停止时给客户端返回状态
 */
class ActionProcessorDelegate {
 public:
  virtual ~ActionProcessorDelegate() = default;

  // Called when all processing in an ActionProcessor has completed. A pointer
  // to the ActionProcessor is passed. |code| is set to the exit code of the
  // last completed action.
  /*
   * 当操作处理器中的所有处理都已完成时调用。
   * 参数:processor 指向 ActionProcessor 的指针;code 表示未上次完成的操作时退出的代码
   */
  virtual void ProcessingDone(const ActionProcessor* processor,
                              ErrorCode code) {}

  // Called when processing has stopped. Does not mean that all Actions have
  // completed. If/when all Actions complete, ProcessingDone() will be called.
  /*
   * 当处理停止时调用。
   * 并不代表着所有动作均已完成。如果当所有动作均已完成,将调用 ProcessingDone()。
   */
  virtual void ProcessingStopped(const ActionProcessor* processor) {}

  // Called whenever an action has finished processing, either successfully
  // or otherwise.
  /*
   * 每当操作完成处理时调用,无论成功与否。
   */
  virtual void ActionCompleted(ActionProcessor* processor,
                               AbstractAction* action,
                               ErrorCode code) {}
};

ActionProcessorは、Action管理クラスとして以下の機能を持っています。

キューへのアクション: EnqueueAction

アクションの開始と停止: StartProcessing StopProcessing

アクションの一時停止と再開: SuspendProcessing ResumeProcessing

アクションの完了と切り替え: ActionComplete StartNextActionOrFinish

デリゲート クラスを設定します: set_delegate

アクションが実行中かどうかを判断します: IsRunning()

アクションが一時停止されているかどうかを判断します:suspended_

ActionProcessorDelegateはデリゲートクラスであり、主に処理中のステータスやイベントをActionProcessに通知するために使用され、その機能は以下の通りです。

アクションがその関数の処理を完了すると、ActionProcessor に ActionCompleted() を呼び出すように通知します。

停止ハンドラーが呼び出されたら、ProcessingStopped() を呼び出します。

ProcessingDone() は、アクション プロセッサ内のすべてのアクションが完了すると呼び出されます。

2.3.1.1.3 アクションパイプ

Unix システムのパイプラインと同様に、アクション メカニズムでも、これらのアクションはパイプライン ActionPipe を介してリンクされます。前のアクションの出力は、次のアクションの入力として使用されます。

したがって、更新エンジンでは、すべてのアクション間に順序関係が存在します。たとえば、FilesystemVerifierAction 操作は DownloadAction の操作が完了した後にのみ開始でき、PostinstallRunnerAction 操作は FilesystemVerifierAction の完了後にのみ開始できます。

ActionPipeクラスの機能は以下の通りです。クラスは「android/system/update_engine/common/action_pipe.h」に定義されています。

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

ここに画像の説明を挿入

// 文件:android/system/update_engine/common/action_pipe.h

class ActionPipe {
 public:
  virtual ~ActionPipe() {}

  // This should be called by an Action on its input pipe.
  // Returns a reference to the stored object.
  /*
   * 此函数应该由 Action 的输入管道调用,用于获取 输入对象 的引用。
   */
  const ObjectType& contents() const { return contents_; }

  // This should be called by an Action on its output pipe.
  // Stores a copy of the passed object in this pipe.
  /*
   * 此函数应该由 Action 的输出管道调用,用于存储一个输出对象的副本。
   */
  void set_contents(const ObjectType& contents) { contents_ = contents; }

  // Bonds two Actions together with a new ActionPipe. The ActionPipe is
  // jointly owned by the two Actions and will be automatically destroyed
  // when the last Action is destroyed.
  /*
   * 将两个操作与新的操作管道绑定在一起,操作管道有两个操作共同拥有,并且在最后一个操作销毁时自动销毁
   * FromAction 表示上一个 Action; ToAction 表示下一个 Action。
   * 上一个 Action 的输出对象跟下一个 Action 的输入对象是同一个。
   */
  template <typename FromAction, typename ToAction>
  static void Bond(FromAction* from, ToAction* to) {
    std::shared_ptr<ActionPipe<ObjectType>> pipe(new ActionPipe<ObjectType>);
    from->set_out_pipe(pipe);

    to->set_in_pipe(pipe);  // If you get an error on this line, then
    // it most likely means that the From object's OutputObjectType is
    // different from the To object's InputObjectType.
    // 如果此行收到错误,则很可能意味着 From 对象的 OutputObjectType 与 To 对象的 InputObjectType 不同。
  }

 private:
  ObjectType contents_;

  // The ctor is private. This is because this class should construct itself
  // via the static Bond() method.
  // 这个构造函数是私有的,这是因为这个类应该通过静态函数 Bond() 方法实现构造。
  ActionPipe() {}
  DISALLOW_COPY_AND_ASSIGN(ActionPipe);
};

Action の入出力オブジェクトはいつ完了しますか?

ActionにはInputObjectとOutputObjectがありますが、これらのオブジェクトはいつ、どのように完成するのでしょうか?

まず答えについて話しましょう。InputObject はこのアクションのパイプライン入力オブジェクトであるため、このアクションの関数が実行される前に取得する必要があり、アクションによって実行される最初の関数は PerformAction() 関数である必要があります。通常、InputObject はこのメソッドで取得されます。OutputObject はこのアクションのパイプライン出力オブジェクトであり、次のアクションの入力オブジェクトでもあるため、アクション関数の実行が完了し、アクションによって最後の関数が実行された後に設定する必要があります。 ActionComplete() 関数である必要があるため、OutputObject は通常、このメソッド呼び出しの前に made に設定されます。

2.3.1.1.4 概要図

一般的に、Action メカニズムは次の図に示されています。UpdateEngine モジュールのアップグレード ステップは Action によって表され、Action の入力オブジェクトと出力オブジェクトは ActionPipe によって制御されます。すべての Action アクションは、ActionPorcessor 管理クラスに格納されます。そして、ActionProcessor 管理クラスは ActionProcessorDelegate を使用します。委任クラスは、アクション操作全体のリズムを制御します。

ここに画像の説明を挿入

2.3.1.2 applyPayload処理

このセクションでは、applyPayload 関数の流れから始まり、クラスの構造から関数の実装までの詳細を説明します。

2.3.1.2.1 BinderUpdateEngineAndroidService クラス

前回の UpdateEngine 起動のプロセス分析から、UpdateEngine の AIDL サーバー オブジェクトは BinderUpdateEngineAndroidService クラスであり、上位層によって取得される UpdateEngine AIDL サーバー オブジェクトは実際には BinderUpdateEngineAndroidService クラス オブジェクトです。このクラスの定義を見てみましょう。

BinderUpdateEngineAndroidService クラス構造図:

ここに画像の説明を挿入

クラス定義から、BinderUpdateEngineAndroidService が android::os::BnUpdateEngine と ServiceObserverInterface を継承していることがわかります。android::os::BnUpdateEngine は AIDL オブジェクトであり、ServiceObserverInterface はコールバック インターフェイス クラスをカプセル化しています。つまり、BinderUpdateEngineAndroidServiceは、上位層の呼び出しと上位層へのコールバック情報を受け取るオブジェクトです。

// 文件:android/system/update_engine/binder_service_android.h

class BinderUpdateEngineAndroidService : public android::os::BnUpdateEngine,
                                         public ServiceObserverInterface {
 public:
  explicit BinderUpdateEngineAndroidService(
      ServiceDelegateAndroidInterface* service_delegate);
  ~BinderUpdateEngineAndroidService() override = default;

  const char* ServiceName() const { return "android.os.UpdateEngineService"; }
  
--------------------------------------------------------------------------------------------------------------------------------
  // ServiceObserverInterface overrides.下面两个函数是来自 ServiceObserverInterface 类,封装了反馈信息给上层的接口
  void SendStatusUpdate(
      const update_engine::UpdateEngineStatus& update_engine_status) override;
  void SendPayloadApplicationComplete(ErrorCode error_code) override;

--------------------------------------------------------------------------------------------------------------------------------
  // android::os::BnUpdateEngine overrides.下面的函数是来自 android::os::BnUpdateEngine 类,AIDL类接口的实现。
  android::binder::Status applyPayload(
      const android::String16& url,
      int64_t payload_offset,
      int64_t payload_size,
      const std::vector<android::String16>& header_kv_pairs) override;
  android::binder::Status bind(
      const android::sp<android::os::IUpdateEngineCallback>& callback,
      bool* return_value) override;
  android::binder::Status unbind(
      const android::sp<android::os::IUpdateEngineCallback>& callback,
      bool* return_value) override;
  android::binder::Status suspend() override;
  android::binder::Status resume() override;
  android::binder::Status cancel() override;
  android::binder::Status resetStatus() override;
  android::binder::Status verifyPayloadApplicable(
      const android::String16& metadata_filename, bool* return_value) override;
      
--------------------------------------------------------------------------------------------------------------------------------
 
 private:
  // Remove the passed |callback| from the list of registered callbacks. Called
  // on unbind() or whenever the callback object is destroyed.
  // Returns true on success.
  // 此函数作用是从注册回调列表中删除传递的回调对象,在上层调用 unbind() 或对象被销毁时调用
  bool UnbindCallback(const IBinder* callback);

  // List of currently bound callbacks. 回调对象列表,用于保存上层 bind() 传下来的回调对象
  std::vector<android::sp<android::os::IUpdateEngineCallback>> callbacks_;

  // Cached copy of the last status update sent. Used to send an initial
  // notification when bind() is called from the client.
  // 发送的最后一次状态更新的缓存副本。用于在从客户端调用 bind() 时发送初始通知。
  int last_status_{-1};
  double last_progress_{0.0};

  // DaemonStateAndroid 类型实例,继承自 ServiceDelegateAndroidInterface,封装了 AIDI 接口,当上层调用 AIDL 接口时,会调用到    
  // DaemonStateAndroid 类中
  ServiceDelegateAndroidInterface* service_delegate_;
};

実際、BinderUpdateEngineAndroidService クラスの実装には AIDL インターフェースの具体的な実装はなく、ServiceDelegateAndroidInterface クラスの applyPayload インターフェースを呼び出すことで具体的に実装されています。

2.3.1.2.2 UpdateAttempterAndroid クラス

ServiceDelegateAndroidInterface は、インターフェイス ファイルに相当します。このクラスは、AIDL インターフェイスに基づいて関数実装インターフェイスを定義します。後続の機能クラスは、このインターフェイスを継承し、特定の機能を提供するメソッドを実装します。サブクラス UpdateAttempterAndroid は、ServiceDelegateAndroidInterface、ActionProcessorDelegate、DownloadActionDelegate、PostinstallRunnerAction: から継承します。 DelegateInterface; UpdateEngine 関数の特定の実装クラスです。

UpdateAttempterAndroid クラス構造図:

ここに画像の説明を挿入

その重要性は、UpdateAttempterAndroid 構造からわかります。ServiceDelegateAndroidInterface は、AIDL インターフェイスを実装するための関数クラスです。DownloadActionDelegate は、アップグレード ステップのダウンロード部分の関数クラスです。PostinstallRunnerAction::DelegateInterface は、アップグレードの PostInstall 部分の関数クラスです。 step; ActionProcessorDelegate は、UpdateEngine 機能クラスの Action メカニズムの機能クラスです。

文件:android/system/update_engine/update_attempter_android.h


class UpdateAttempterAndroid
    : public ServiceDelegateAndroidInterface,
      public ActionProcessorDelegate,
      public DownloadActionDelegate,
      public PostinstallRunnerAction::DelegateInterface {
 public:
  using UpdateStatus = update_engine::UpdateStatus;

  UpdateAttempterAndroid(DaemonStateInterface* daemon_state,
                         PrefsInterface* prefs,
                         BootControlInterface* boot_control_,
                         HardwareInterface* hardware_);
  ~UpdateAttempterAndroid() override;

  // Further initialization to be done post construction.
  void Init();
  
--------------------------------------------------------------------------------------------------------------------------------
下面是 ServiceDelegateAndroidInterface 的接口实现

  // ServiceDelegateAndroidInterface overrides.
  /*
   * 触发升级接口
   */
  bool ApplyPayload(const std::string& payload_url,
                    int64_t payload_offset,
                    int64_t payload_size,
                    const std::vector<std::string>& key_value_pair_headers,
                    brillo::ErrorPtr* error) override;
  /*
   * 暂停升级
   * 函数实现中会调用 ActionProcessor->SuspendProcessing() 方法暂停处理。
   */
  bool SuspendUpdate(brillo::ErrorPtr* error) override;
  /*
   * 继续升级
   * 函数实现中会调用 ActionProcessor->ResumeProcessing() 方法恢复处理。
   */
  bool ResumeUpdate(brillo::ErrorPtr* error) override;
  /*
   * 取消升级
   * 函数实现中会调用 ActionProcessor->StopProcessing() 方法停止升级。
   */
  bool CancelUpdate(brillo::ErrorPtr* error) override;
  /*
   * 重置升级状态
   * 函数实现中会根据当前的状态做出重置
   * 当前如果是 IDLE 状态,那么不用处理,直接 return;
   * 当前如果是升级完成,需要重启的状态,那么此时现清除 kPrefsUpdateCompletedOnBootId 标记,更新 boot 标记,将当前分区设置为正常启动分区,重置当前状
   * 态为 IDLE 并通知客户端重置成功。
   * 当前如果是其他状态,不允许重置的操作,需要先取消正在进行的升级,会返回一个 Error。
   */
  bool ResetStatus(brillo::ErrorPtr* error) override;
  /*
   * 判断此升级包是否可以应用与本机升级
   * 函数实现中会根据升级包的参数,解析升级包并校验,判断是否能够进行升级。
   */
  bool VerifyPayloadApplicable(const std::string& metadata_filename,
                               brillo::ErrorPtr* error) override;

--------------------------------------------------------------------------------------------------------------------------------
下面是 ActionProcessorDelegate 接口实现

  // ActionProcessorDelegate methods:
  /*
   * 当 Action 队列中的 Action 均执行结束后 或者 Action 执行过程中有报错退出时触发。
   * 此函数由 ActionProcessor::StartNextActionOrFinish() 调用。
   * 函数实现
   * 1、根据传入的 ErrorCode 判断
   * 2、如果是升级成功,写入升级成功的标记
   * 3、如果是升级失败,重置升级
   * 4、如果是 payload 时间戳错误,写入错误并停止
   * 5、最后结束升级并通知
   */
  void ProcessingDone(const ActionProcessor* processor,
                      ErrorCode code) override;
  /*
   * 停止升级接口
   * 此函数由 ActionProcessor::StopProcessing() 调用
   * 函数实现
   * 终止升级并进行通知,使用的 ErrorCode 为用户取消升级
   */
  void ProcessingStopped(const ActionProcessor* processor) override;
  /*
   * Action 动作执行结束函数
   * 此函数由 ActionProcessor::ActionComplete() 调用
   * 函数实现
   * 1、首先获取当前 Action 是哪个 Action
   * 2、对于不同的 Action 做出对应的结束成功的判断
   * 3、如果当前 Action 的执行结果不是成功状态,表明此 Action 的执行是失败的,直接 return
   * 4、在当前状态成功的情况下,通知客户端升级状态
   */
  void ActionCompleted(ActionProcessor* processor,
                       AbstractAction* action,
                       ErrorCode code) override;

--------------------------------------------------------------------------------------------------------------------------------
下面是 DownloadActionDelegate 接口的实现

  // DownloadActionDelegate overrides.
  /*
   * 下载数据接收接口
   * 此函数在下载过程中会频繁的被调用,下载的数据是分包下载的,此函数会计算下载的进度、写入当前已下载的数据量和总数据量,并且判断是否下载完成,下载完成就调用
   * SetStatusAndNotify() 函数通知下载完成状态;如果没有下载完成,就持续调用 ProgressUpdate() 函数报告进度。
   */
  void BytesReceived(uint64_t bytes_progressed,
                     uint64_t bytes_received,
                     uint64_t total) override;
  /*
   * 取消下载接口
   * 此函数是空实现
   */
  bool ShouldCancel(ErrorCode* cancel_reason) override;
  /*
   * 下载完成接口
   * 此函数是空实现
   */
  void DownloadComplete() override;

--------------------------------------------------------------------------------------------------------------------------------
下面是 PostInstallRunnerAction::DelegateInterface 接口实现

  // PostinstallRunnerAction::DelegateInterface
  /*
   * 下载进度更新接口
   * 函数实现会基于进度进行判断,如果进度太慢,会发送通知。
   */
  void ProgressUpdate(double progress) override;

--------------------------------------------------------------------------------------------------------------------------------

 private:
  friend class UpdateAttempterAndroidTest;

  // Schedules an event loop callback to start the action processor. This is
  // scheduled asynchronously to unblock the event loop.
  void ScheduleProcessingStart();

  // Notifies an update request completed with the given error |code| to all
  // observers.
  void TerminateUpdateAndNotify(ErrorCode error_code);

  // Sets the status to the given |status| and notifies a status update to
  // all observers.
  void SetStatusAndNotify(UpdateStatus status);

  // Helper method to construct the sequence of actions to be performed for
  // applying an update using a given HttpFetcher. The ownership of |fetcher| is
  // passed to this function.
  void BuildUpdateActions(HttpFetcher* fetcher);

  // Writes to the processing completed marker. Does nothing if
  // |update_completed_marker_| is empty.
  bool WriteUpdateCompletedMarker();

  // Returns whether an update was completed in the current boot.
  bool UpdateCompletedOnThisBoot();

  // Prefs to use for metrics report
  // |kPrefsPayloadAttemptNumber|: number of update attempts for the current
  // payload_id.
  // |KprefsNumReboots|: number of reboots when applying the current update.
  // |kPrefsSystemUpdatedMarker|: end timestamp of the last successful update.
  // |kPrefsUpdateTimestampStart|: start timestamp in monotonic time of the
  // current update.
  // |kPrefsUpdateBootTimestampStart|: start timestamp in boot time of
  // the current update.
  // |kPrefsCurrentBytesDownloaded|: number of bytes downloaded for the current
  // payload_id.
  // |kPrefsTotalBytesDownloaded|: number of bytes downloaded in total since
  // the last successful update.

  // Metrics report function to call:
  //   |ReportUpdateAttemptMetrics|
  //   |ReportSuccessfulUpdateMetrics|
  // Prefs to update:
  //   |kPrefsSystemUpdatedMarker|
  void CollectAndReportUpdateMetricsOnUpdateFinished(ErrorCode error_code);

  // Metrics report function to call:
  //   |ReportAbnormallyTerminatedUpdateAttemptMetrics|
  //   |ReportTimeToRebootMetrics|
  // Prefs to update:
  //   |kPrefsBootId|, |kPrefsPreviousVersion|
  void UpdatePrefsAndReportUpdateMetricsOnReboot();

  // Prefs to update:
  //   |kPrefsPayloadAttemptNumber|, |kPrefsUpdateTimestampStart|,
  //   |kPrefsUpdateBootTimestampStart|
  void UpdatePrefsOnUpdateStart(bool is_resume);

  // Prefs to delete:
  //   |kPrefsNumReboots|, |kPrefsCurrentBytesDownloaded|
  //   |kPrefsSystemUpdatedMarker|, |kPrefsUpdateTimestampStart|,
  //   |kPrefsUpdateBootTimestampStart|
  void ClearMetricsPrefs();

  DaemonStateInterface* daemon_state_;

  // DaemonStateAndroid pointers.
  PrefsInterface* prefs_;
  BootControlInterface* boot_control_;
  HardwareInterface* hardware_;

  // Last status notification timestamp used for throttling. Use monotonic
  // TimeTicks to ensure that notifications are sent even if the system clock is
  // set back in the middle of an update.
  base::TimeTicks last_notify_time_;

  // Only direct proxy supported.
  DirectProxyResolver proxy_resolver_;

  // The processor for running Actions.
  std::unique_ptr<ActionProcessor> processor_;

  // The InstallPlan used during the ongoing update.
  InstallPlan install_plan_;

  // For status:
  UpdateStatus status_{UpdateStatus::IDLE};
  double download_progress_{0.0};

  // The offset in the payload file where the CrAU part starts.
  int64_t base_offset_{0};

  // Helper class to select the network to use during the update.
  std::unique_ptr<NetworkSelectorInterface> network_selector_;

  std::unique_ptr<ClockInterface> clock_;

  std::unique_ptr<MetricsReporterInterface> metrics_reporter_;

  DISALLOW_COPY_AND_ASSIGN(UpdateAttempterAndroid);
};

2.3.1.2.3 applyPayload関数の実装

次に、UpdateAttempterAndroid の applyPayload() の実装に入り、アップグレード プロセスの分析を開始します。

文件:android/system/update_engine/update_attempter_android.cc
/*
 * 从 ApplyPayload 接口实现代码中,整个过程做的事情有很多,我们得把具体实现进行分步分析,以免绕晕...
 */
 
bool UpdateAttempterAndroid::ApplyPayload(
    const string& payload_url,
    int64_t payload_offset,
    int64_t payload_size,
    const vector<string>& key_value_pair_headers,
    brillo::ErrorPtr* error) {
--------------------------------------------------------------------------------------------------------------------------------
关于入参
string payload_url:内容举例 “file:///storage/798A-ECED/usb_ota_update.zip”,是升级包的路径

int payload_offset:内容举例 offset=659 表示的数据的偏移量,下载的时候会从这个偏移量之后开始下载,是数据的开始

int payload_size:内容举例 size=2447066254 表示数据的长度

vector<string> key_value_pair_headers:此内容是一个 String 格式的数据集合,内容如下:
	[
		FILE_HASH=PLo9cSeCeECAhKHlk06drRFHCyd1BGHE/fliEd0F3uQ=, 
		FILE_SIZE=2447066254, 
		METADATA_HASH=H+gFeOLUWil1LyX4VOJIhGvHHv+MrFu1RBdxXzhorHQ=, 
		METADATA_SIZE=179338
	]
	可以发现是 payload_properties.txt 中的内容

billlo::ErrorPtr error: error 信息

--------------------------------------------------------------------------------------------------------------------------------
下面两个条件判断是先对升级的状态进行判断,在升级前,根据状态判断是否已经升级完毕需要重启;判断是否已经有一个升级正在进行中。
当上述两种场景时,上层触发升级的话,会直接上报一个 Error 返回给应用。并不会触发升级。

  if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) {
    return LogAndSetError(
        error, FROM_HERE, "An update already applied, waiting for reboot");
  }
  if (processor_->IsRunning()) {
    return LogAndSetError(
        error, FROM_HERE, "Already processing an update, cancel it first.");
  }
  DCHECK(status_ == UpdateStatus::IDLE);
  
--------------------------------------------------------------------------------------------------------------------------------
下面步骤是对于 入参 key_value_pair_headers 内容拆分存储到 headers 集合中。

  std::map<string, string> headers;
  for (const string& key_value_pair : key_value_pair_headers) {
    string key;
    string value;
    if (!brillo::string_utils::SplitAtFirst(
            key_value_pair, "=", &key, &value, false)) {
      return LogAndSetError(
          error, FROM_HERE, "Passed invalid header: " + key_value_pair);
    }
    if (!headers.emplace(key, value).second)
      return LogAndSetError(error, FROM_HERE, "Passed repeated key: " + key);
  }

--------------------------------------------------------------------------------------------------------------------------------
创建一个 payload_id,这个 payload_id 的内容是 headers 集合中两个数据的组合,表示的是这个升级数据包的唯一标识
headers[kPayloadPropertyFileHash] = headers[FILE_HASH]
headers[kPayloadPropertyMetadataHash] = headers[METADATA_HASH]
那么 payload_id 的内容就是:PLo9cSeCeECAhKHlk06drRFHCyd1BGHE/fliEd0F3uQ=H+gFeOLUWil1LyX4VOJIhGvHHv+MrFu1RBdxXzhorHQ=
由于两个数据是 Hash 值,可以标识此数据包

  // Unique identifier for the payload. An empty string means that the payload
  // can't be resumed.
  string payload_id = (headers[kPayloadPropertyFileHash] +
                       headers[kPayloadPropertyMetadataHash]);

--------------------------------------------------------------------------------------------------------------------------------
下面是根据升级请求创建 InstallPlan
关于 InstallPlan 结构体的描述在下面会分析。
此结构体从流程上看还是比较重要的,描述了升级过程中的安装计划,也是作为 Action 的输入输出对象一直出现在 Action 的执行过程中的。

  // Setup the InstallPlan based on the request.
  install_plan_ = InstallPlan();

  install_plan_.download_url = payload_url;
  install_plan_.version = "";
  base_offset_ = payload_offset;
  
  // 创建 InstallPlan 结构体中的 Payload 结构体
  InstallPlan::Payload payload;
  payload.size = payload_size;
  if (!payload.size) {
    if (!base::StringToUint64(headers[kPayloadPropertyFileSize],
                              &payload.size)) {
      payload.size = 0;
    }
  }
  if (!brillo::data_encoding::Base64Decode(headers[kPayloadPropertyFileHash],
                                           &payload.hash)) {
    LOG(WARNING) << "Unable to decode base64 file hash: "
                 << headers[kPayloadPropertyFileHash];
  }
  if (!base::StringToUint64(headers[kPayloadPropertyMetadataSize],
                            &payload.metadata_size)) {
    payload.metadata_size = 0;
  }
  // The |payload.type| is not used anymore since minor_version 3.
  payload.type = InstallPayloadType::kUnknown;
  // 为 Payload 结构体赋值后,将对象放入到 install_plan_.payloads 容器中。
  install_plan_.payloads.push_back(payload);

  // The |public_key_rsa| key would override the public key stored on disk.
  install_plan_.public_key_rsa = "";

  install_plan_.hash_checks_mandatory = hardware_->IsOfficialBuild();
  // 判断是否进行未完成的升级。是一次 全新升级(new update) 还是 恢复上一次升级(resume)。 
  install_plan_.is_resume = !payload_id.empty() &&
                            DeltaPerformer::CanResumeUpdate(prefs_, payload_id);
  if (!install_plan_.is_resume) {
    if (!DeltaPerformer::ResetUpdateProgress(prefs_, false)) {
      LOG(WARNING) << "Unable to reset the update progress.";
    }
    if (!prefs_->SetString(kPrefsUpdateCheckResponseHash, payload_id)) {
      LOG(WARNING) << "Unable to save the update check response hash.";
    }
  }
  // source_slot 表示当前正在运行的分区
  install_plan_.source_slot = boot_control_->GetCurrentSlot();
  // target_slot 表示需要升级的分区
  install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0;

  install_plan_.powerwash_required =
      GetHeaderAsBool(headers[kPayloadPropertyPowerwash], false);

// 选择哪个分区进行重启。
  install_plan_.switch_slot_on_reboot =
      GetHeaderAsBool(headers[kPayloadPropertySwitchSlotOnReboot], true);

// 需要执行 run_post_install 步骤。
  install_plan_.run_post_install = true;
  // Optionally skip post install if and only if:
  // a) we're resuming
  // b) post install has already succeeded before
  // c) RUN_POST_INSTALL is set to 0.
  /*
   *(可选)在以下情况下跳过 run_post_install 步骤:
   * a) 我们正在恢复
   * b) 安装后在之前已经成功
   * c) RUN_POST_INSTALL设置为 0。
   */
  if (install_plan_.is_resume && prefs_->Exists(kPrefsPostInstallSucceeded)) {
    bool post_install_succeeded = false;
    if (prefs_->GetBoolean(kPrefsPostInstallSucceeded,
                           &post_install_succeeded) &&
        post_install_succeeded) {
      install_plan_.run_post_install =
          GetHeaderAsBool(headers[kPayloadPropertyRunPostInstall], true);
    }
  }

  // Skip writing verity if we're resuming and verity has already been written.
  install_plan_.write_verity = true;
  if (install_plan_.is_resume && prefs_->Exists(kPrefsVerityWritten)) {
    bool verity_written = false;
    if (prefs_->GetBoolean(kPrefsVerityWritten, &verity_written) &&
        verity_written) {
      install_plan_.write_verity = false;
    }
  }

  NetworkId network_id = kDefaultNetworkId;
  if (!headers[kPayloadPropertyNetworkId].empty()) {
    if (!base::StringToUint64(headers[kPayloadPropertyNetworkId],
                              &network_id)) {
      return LogAndSetError(
          error,
          FROM_HERE,
          "Invalid network_id: " + headers[kPayloadPropertyNetworkId]);
    }
    if (!network_selector_->SetProcessNetwork(network_id)) {
      return LogAndSetError(
          error,
          FROM_HERE,
          "Unable to set network_id: " + headers[kPayloadPropertyNetworkId]);
    }
  }

  LOG(INFO) << "Using this install plan:";
  // 一直到这里,InstallPlan 结构体参数设置完成了。这里会输出 InstallPlan 中的参数,其实现在 install_plan.cc 中。
  install_plan_.Dump();

--------------------------------------------------------------------------------------------------------------------------------
下面是对 HttpFetcher 类做 URL升级文件路径判断与 headers Map集合的额外配置
判断:判断当前传过来的路径是否支持下载,仅支持的 url 路径必须以 "file:///" 开始
配置:如果 headers[AUTHORIZATION] 和 headers[USER_AGENT] 配置项为空,那么进行默认配置
		headers[AUTHORIZATION] = "Authorization"
		headers[USER_AGENT] = "User-Agent"
	
  HttpFetcher* fetcher = nullptr;
  if (FileFetcher::SupportedUrl(payload_url)) {
    DLOG(INFO) << "Using FileFetcher for file URL.";
    fetcher = new FileFetcher();
  } else {
#ifdef _UE_SIDELOAD
    LOG(FATAL) << "Unsupported sideload URI: " << payload_url;
#else
    LibcurlHttpFetcher* libcurl_fetcher =
        new LibcurlHttpFetcher(&proxy_resolver_, hardware_);
    libcurl_fetcher->set_server_to_check(ServerToCheck::kDownload);
    fetcher = libcurl_fetcher;
#endif  // _UE_SIDELOAD
  }
  // Setup extra headers.
  if (!headers[kPayloadPropertyAuthorization].empty())
    fetcher->SetHeader("Authorization", headers[kPayloadPropertyAuthorization]);
  if (!headers[kPayloadPropertyUserAgent].empty())
    fetcher->SetHeader("User-Agent", headers[kPayloadPropertyUserAgent]);

--------------------------------------------------------------------------------------------------------------------------------
到这里一些准备工作就已经差不多结束了,要开始准备升级的动作了。

// 创建升级的各种 Action。前面提到的 UpdateEngine 模块的 Action 就是这里完成的。
  BuildUpdateActions(fetcher);

// 回调给客户端当前升级状态为 UPDATE_AVAILABLE
  SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);

// 保存更新开始时间。如果更新不是恢复,则重置重新启动计数和尝试次数;否则递增尝试次数。
  UpdatePrefsOnUpdateStart(install_plan_.is_resume);
  // TODO(xunchang) report the metrics for unresumable updates

// 这里是开启了 ActionProcessor 中的 Action 调度,开始执行 Action。
/*
 * 问题:是否开启了新的线程
 * 参考链接:
 * https://keyou.github.io/blog/2019/06/11/Chromium-MessageLoop-and-TaskScheduler/
 * https://blog.csdn.net/Mirage520/article/details/41699347
 * 
 * 我们先来看下这里的实现,这里调用了 PostTask() 函数去调用 ActionProcessor->StartProcessing() 函数
 * brillo::MessageLoop::current()->PostTask(
      FROM_HERE,
      Bind([](ActionProcessor* processor) { processor->StartProcessing(); },
           base::Unretained(processor_.get())));
 *
 * 关于 PostTask() 函数,搜索到的理解是向当前线程调用 PostTask() 函数向 线程池 里创建任务,那么这里的执行是否会在新的线程里执行呢?
 * 从日志上看,升级的动作是在主进程中完成的。
 */
  ScheduleProcessingStart();
  return true;
}

applyPayload メソッドの内容を要約すると、次のようになります。

1. アップグレードのステータスを確認する

2. 受信パラメータを解析する

3. 受信パラメータを install_plan_ 構造体に設定します。

4. さまざまなアクションの作成とアップグレード

5. 現在のアップグレード ステータスをクライアントにコールバックします。

6. ActionProcessorでActionの動作を開始する

2.3.1.2.4 BuildUpdateActions関数の実装

applyPayload() アップグレード トリガー インターフェイスでは、アクション アクションの作成プロセスは BuildUpdateActions によって完了します。アクションを作成する実装プロセスを分析してみましょう。

文件:android/system/update_engine/update_attempter_android.cc

// 创建升级过程中的 Action。
void UpdateAttempterAndroid::BuildUpdateActions(HttpFetcher* fetcher) {
  CHECK(!processor_->IsRunning());
  
  // 设置 ActionProcessor 管理类的委托对象,UpdateAttempterAndroid 类继承自 ActionProcessorDelegate 类。
  processor_->set_delegate(this);

  // Actions:
  /*
   * 下面是创建 Action。
   * Action 依次是:
   *	UpdateBootFlagsAction
   *	InstallPlanAction
   *	DownloadAction
   *	FilesystemVerifierAction
   *	PostinstallRunnerAction
   * 
   */
  auto update_boot_flags_action =
      std::make_unique<UpdateBootFlagsAction>(boot_control_);
      
  auto install_plan_action = std::make_unique<InstallPlanAction>(install_plan_);
  
  auto download_action =
      std::make_unique<DownloadAction>(prefs_,
                                       boot_control_,
                                       hardware_,
                                       nullptr,  // system_state, not used.
                                       fetcher,  // passes ownership
                                       true /* interactive */);
  // 设置 DownloadAction 类的委托对象,UpdateAttempterAndroid 类继承自 DownloadActionDelegate 类。
  download_action->set_delegate(this);
  download_action->set_base_offset(base_offset_);
  
  auto filesystem_verifier_action =
      std::make_unique<FilesystemVerifierAction>();
      
  auto postinstall_runner_action =
      std::make_unique<PostinstallRunnerAction>(boot_control_, hardware_);
  // 设置 PostinstallRunnerAction 类的委托对象,UpdateAttempterAndroid 类继承自 PostinstallRunnerAction::DelegateInterface 类。
  postinstall_runner_action->set_delegate(this);

  // Bond them together. We have to use the leaf-types when calling
  // BondActions().
  // 通过调用 BondActions() 函数将 Action 之间通过 ActionPipe 连接起来。
  BondActions(install_plan_action.get(), download_action.get());
  BondActions(download_action.get(), filesystem_verifier_action.get());
  BondActions(filesystem_verifier_action.get(),
              postinstall_runner_action.get());

  // 将创建的 Action 依次放入 ActionProcessor 的队列中。
  processor_->EnqueueAction(std::move(update_boot_flags_action));
  processor_->EnqueueAction(std::move(install_plan_action));
  processor_->EnqueueAction(std::move(download_action));
  processor_->EnqueueAction(std::move(filesystem_verifier_action));
  processor_->EnqueueAction(std::move(postinstall_runner_action));

  processor_->printActions();
}

2.3.1.2.5 ScheduleProcessingStart関数の実装

applyPayload インターフェイスの実装では、ScheduleProcessingStart() 関数が呼び出され、ActionProcessor でアクションの実行が開始されます。

文件:android/system/update_engine/update_attempter_android.cc

/*
 * 调用 PostTask() 函数执行 ActionProcessor->StartProcessing() 方法开启 Action 动作执行。
 */
void UpdateAttempterAndroid::ScheduleProcessingStart() {
  LOG(INFO) << "Scheduling an action processor start.";
  brillo::MessageLoop::current()->PostTask(
      FROM_HERE,
      Bind([](ActionProcessor* processor) { processor->StartProcessing(); },
           base::Unretained(processor_.get())));
}

アクションがどのように実行されるかを追跡してみましょう。

文件:android/system/update_engine/common/action_processor.cc

/*
 * 开启 ActionProcessor 中 Action 的执行。
 */
void ActionProcessor::StartProcessing() {
  CHECK(!IsRunning());
  // 如果当前 Action 队列中有 Action,则进行处理,否则无处理。
  if (!actions_.empty()) {
    // 获取 actions_ 队列中的第一个 Action 赋值给 current_action。
    current_action_ = std::move(actions_.front());
    // 将 actions_ 队列中的第一个 Action 移出队列。
    actions_.pop_front();
    LOG(INFO) << "ActionProcessor: starting " << current_action_->Type();
    // 调用 Action 的 performAction() 函数执行 Action 的功能。
    current_action_->PerformAction();
  }
}

2.3.1.3 InstallPlan 構造の分析

前述したように、InstallPlan 構造はアップグレード全体に関係しており、ほとんどの Action アクションの入力オブジェクトおよび出力オブジェクトです。

InstallPlan 構造内のデータはアップグレード パッケージから解析され、この構造はアップグレード プロセス中に継続的に入力され、最終的にアップグレードが完了します。

InstallPlan の構造を次の図に示します。

ここに画像の説明を挿入

 struct InstallPlan {
  InstallPlan() = default;

  bool operator==(const InstallPlan& that) const;
  bool operator!=(const InstallPlan& that) const;

  void Dump() const;

  // Loads the |source_path| and |target_path| of all |partitions| based on the
  // |source_slot| and |target_slot| if available. Returns whether it succeeded
  // to load all the partitions for the valid slots.
  bool LoadPartitionsFromSlots(BootControlInterface* boot_control); // 获取 source_slot 和 target_slot 中的分区路径

  bool is_resume{false};  // 是否未更新完成,需要恢复更新
  std::string download_url;  // url to download from  升级文件的 url
  std::string version;       // version we are installing.  版本号
  // system version, if present and separate from version
  std::string system_version;  // 系统版本号

  struct Payload {
    uint64_t size = 0;               // size of the payload  升级包 payload.bin 的大小
    uint64_t metadata_size = 0;      // size of the metadata  元数据 metadata 的大小
    std::string metadata_signature;  // signature of the metadata in base64  元数据的签名 base64 格式
    brillo::Blob hash;               // SHA256 hash of the payload  升级包 payload.bin 的 hash 值
    InstallPayloadType type{InstallPayloadType::kUnknown};  // 升级包的类型{kUnknown:未知 kFull:整包升级 kDelta:差分升级}
    // Only download manifest and fill in partitions in install plan without
    // apply the payload if true. Will be set by DownloadAction when resuming
    // multi-payload.
    bool already_applied = false;  // 升级包是否已经被应用,如果为 true,则仅下载清单并填写安装计划中的密码,而不应用有效负载。将在 DownloadAction 阶段恢复多有效负载时由下载操作设置。

    bool operator==(const Payload& that) const {
      return size == that.size && metadata_size == that.metadata_size &&
             metadata_signature == that.metadata_signature &&
             hash == that.hash && type == that.type &&
             already_applied == that.already_applied;
    }
  };
  std::vector<Payload> payloads;
  
  // The partition slots used for the update.
  BootControlInterface::Slot source_slot{BootControlInterface::kInvalidSlot};  // 定义 source_slot
  BootControlInterface::Slot target_slot{BootControlInterface::kInvalidSlot};  // 定义 target_slot

  // The vector below is used for partition verification. The flow is:
  //
  // 1. DownloadAction fills in the expected source and target partition sizes
  // and hashes based on the manifest.
  //
  // 2. FilesystemVerifierAction computes and verifies the partition sizes and
  // hashes against the expected values.
  struct Partition {
    bool operator==(const Partition& that) const;

    // The name of the partition.
    std::string name;  // 分区名

    std::string source_path;  // 在 source_slot 中的位置
    uint64_t source_size{0};  // 在 source_slot 大小
    brillo::Blob source_hash;  // 在 source_slot 中的 hash 值

    std::string target_path;  // 在 target_slot 中的位置
    uint64_t target_size{0};  // 在 target_slot 中大小
    brillo::Blob target_hash;  // 在 target_slot 中的 hash 值
    uint32_t block_size{0};

    // Whether we should run the postinstall script from this partition and the
    // postinstall parameters.
    bool run_postinstall{false};
    std::string postinstall_path;
    std::string filesystem_type;  // 文件系统类型
    bool postinstall_optional{false};

    // Verity hash tree and FEC config. See update_metadata.proto for details.
    // All offsets and sizes are in bytes.
    uint64_t hash_tree_data_offset{0};
    uint64_t hash_tree_data_size{0};
    uint64_t hash_tree_offset{0};
    uint64_t hash_tree_size{0};
    std::string hash_tree_algorithm;
    brillo::Blob hash_tree_salt;

    uint64_t fec_data_offset{0};
    uint64_t fec_data_size{0};
    uint64_t fec_offset{0};
    uint64_t fec_size{0};
    uint32_t fec_roots{0};
  };
  std::vector<Partition> partitions;

  // True if payload hash checks are mandatory based on the system state and
  // the Omaha response.
  bool hash_checks_mandatory{false};  // 是否进行强制 HASH 检测

  // True if Powerwash is required on reboot after applying the payload.
  // False otherwise.
  bool powerwash_required{false};  // 是否在升级后进行数据擦除

  // True if the updated slot should be marked active on success.
  // False otherwise.
  bool switch_slot_on_reboot{true};  // 是否在升级成功后标记分区启动状态

  // True if the update should run its post-install step.
  // False otherwise.
  bool run_post_install{true};

  // True if this update is a rollback.
  bool is_rollback{false};

  // True if the update should write verity.
  // False otherwise.
  bool write_verity{true};

  // If not blank, a base-64 encoded representation of the PEM-encoded
  // public key in the response.
  std::string public_key_rsa;  // 公钥,此密钥已经内置到系统中
};

ソースは現在実行中のシステムを表し、ターゲットは現時点でのスタンバイ システムを表します。

新しいバージョンを検出するためにアップグレードする場合、新しいバージョンはソース システムに従って検出され、アップグレードする場合、最初にソース システムがターゲットにコピーされ、次にソース システムがターゲットにコピーされるため、ソース システムを古いシステムとみなすこともできます。アップグレード パッケージが使用されます。 ターゲット システムをアップグレードします。

2.3.2 コールバック処理

前述したように、BinderUpdateEngineAndroidService は、aidl インターフェイスとコールバックの実装をカプセル化します。BinderUpdateEngineAndroidService は、android::os::BnUpdateEngine と ServiceObserverInterface を継承します。android::os::BnUpdateEngine は AIDL オブジェクトで、ServiceObserverInterface はコールバック インターフェイス クラスをカプセル化します。ここではまず、ServiceObserverInterface クラスのコールバック メソッドの定義を確認します。

文件:android/system/update_engine/service_observer_interface.h

class ServiceObserverInterface {
 public:
  virtual ~ServiceObserverInterface() = default;

  // Called whenever the value of these parameters changes. For |progress|
  // value changes, this method will be called only if it changes significantly.
  // 回调升级状态和升级进度给上层
  virtual void SendStatusUpdate(
      const update_engine::UpdateEngineStatus& update_engine_status) = 0;

  // Called whenever an update attempt is completed.
  // 回调升级结果给上层
  virtual void SendPayloadApplicationComplete(ErrorCode error_code) = 0;

 protected:
  ServiceObserverInterface() = default;
};

ServiceObserverInterface はコールバック インターフェイスを定義します。BinderUpdateEngineAndroidService は ServiceObserverInterface クラスを継承し、コールバックの実装を提供します。関数の実装を追跡してみましょう。

文件:android/system/update_engine/binder_service_android.cc

--------------------------------------------------------------------------------------------------------------------------------
这里在描述回调流程之前,我们先分析下绑定回调的流程,以便于对整个回调有清晰的了解

// 绑定回调流程
// 上层通过 bind 接口将 callback 对象传递到底层。
Status BinderUpdateEngineAndroidService::bind(
    const android::sp<IUpdateEngineCallback>& callback, bool* return_value) {
  // 将上层传递下来的 callback 对象放入到 callbacks_ 集合中保存。
  // callbacks_ 集合是专门来保存上层传递的 Callback 对象的。
  // 那么回调对象的绑定也就是将 callback 对象保存起来。
  callbacks_.emplace_back(callback);

  // 调用 RegisterForDeathNotifications 函数确保传递下来的 callback 对象是存在的。
  const android::sp<IBinder>& callback_binder =
      IUpdateEngineCallback::asBinder(callback);
  auto binder_wrapper = android::BinderWrapper::Get();
  binder_wrapper->RegisterForDeathNotifications(
      callback_binder,
      base::Bind(
          base::IgnoreResult(&BinderUpdateEngineAndroidService::UnbindCallback),
          base::Unretained(this),
          base::Unretained(callback_binder.get())));

  // Send an status update on connection (except when no update sent so far),
  // since the status update is oneway and we don't need to wait for the
  // response.
  // 对于进度的判断,如果存在进度的话,则将进度同步回调上层告知此时的升级进度。
  if (last_status_ != -1)
    callback->onStatusUpdate(last_status_, last_progress_);

  *return_value = true;
  return Status::ok();
}

--------------------------------------------------------------------------------------------------------------------------------
回调接口实现

// 回调升级状态和升级进度
void BinderUpdateEngineAndroidService::SendStatusUpdate(
    const UpdateEngineStatus& update_engine_status) {
  // 获取升级的状态
  last_status_ = static_cast<int>(update_engine_status.status);
  // 通过 update_engine_status 获取升级的进度
  last_progress_ = update_engine_status.progress;
  // 遍历 callbacks_ 集合,调用对象的 onStatusUpdate 方法将升级的状态和升级的进度回调给上层
  for (auto& callback : callbacks_) {
    callback->onStatusUpdate(last_status_, last_progress_);
  }
}

// 回调升级结果
void BinderUpdateEngineAndroidService::SendPayloadApplicationComplete(
    ErrorCode error_code) {
  // 遍历 callbacks_ 集合,调用对象的 onPayloadApplicationComplete 方法将升级的结果回调给上层
  for (auto& callback : callbacks_) {
    callback->onPayloadApplicationComplete(static_cast<int>(error_code));
  }
}

次へ: Android UpdateEngine モジュール分析 (4) UpdateEngine アップグレード ロジック


----------
著者:Yang_Mao_Shan
出典:CSDN
原文:https://blog.csdn.net/Yang_Mao_Shan/article/details/131637570
著作権表示:これ記事 著者のオリジナル記事。転載する場合はブログ投稿のリンクを添付してください。
コンテンツ分析 作成者: CSDN、CNBLOG ブログ投稿ワンクリック再版プラグイン

おすすめ

転載: blog.csdn.net/xiaowang_lj/article/details/132028660