Android UpdateEngine Module Analysis (3) Upgrade Trigger and Action Mechanism Introduction

foreword

We have analyzed the compilation and startup process of the UpdateEngine module before, and have a preliminary understanding of the UpdateEngine module. Next, we will start from the upgrade function and analyze the update process of the UpdateEngine. Start the analysis. There are many steps in the update process of UpdateEngine, and each step is controlled by an Action. Therefore, we first explain the Action mechanism of the UpdateEngine module, and describe the triggering method and implementation process of the upgrade.

Previous: Android UpdateEngine Module Analysis (2) UpdateEngine Service Start
Next: Android UpdateEngine Module Analysis (4) UpdateEngine Upgrade Logic

text

There are two ways to trigger the update of UpdateEngine:

The first is to trigger in the form of a command line client, which is triggered by the update_engine_client tool in the command line;

The second is to use the native interface provided by Android to trigger. Here, the trigger method is based on the communication between the Aidl interface and the UpdateEngine, and is triggered according to the process;

1. update_engine_client command line

When using the update_engine_client command line to trigger the upgrade, you need to decompress the zip upgrade package of the SOC first, and get the file in the following format:

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

The update_engine_client command format is:

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

Then enter the adb shell in the cmd command line . Enter the upgrade command:

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"

After the upgrade is complete, you can use cat proc/cmdline to view the AB partition switching before and after the upgrade, and judge whether the upgrade is successful. "androidboot.slot_suffix" represents the current running partition, as shown below:

:/ # 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 interface

In the Android source code, Google provides an apk named SystemUpdater to upgrade the SOC demo on the local USB disk, which can be understood as a demo application describing the call process of the update_engine interface. Next, we will start with this application, start from the interface call process, and analyze the process of using the native interface upgrade according to the process.

2.1 Apply SystemUpdater

2.1.1 Introduction to SystemUpdater

The code directory of the SystemUpdater application is: android/packages/apps/Car/SystemUpdater

Application start command: adb shell am start -n com.android.car.systemupdater.SystemUpdaterActivity

The main functions are:

​ Read the upgrade file in the U disk, and the user clicks the target upgrade file

​ Register the UpdateEngine upgrade progress and result callback, call the UpdateEngine upgrade interface to pass the upgrade parameters to trigger the upgrade

​ Notify powermanager to restart the machine after the upgrade

The code files are:

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

2.2.2 SystemUpdater key process

The following is the timing diagram of the SystemUpdater call:

insert image description here

For the upgrade, two steps are necessary, the first is to register the callback of the upgrade progress and result; the second is to trigger the upgrade.

The following is part of the code of SystemUpdater related to upgrade:


/** 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 architecture

The following figure is the Architecture Diagram of UpdateEngine

insert image description here

UpdateEngine module structure description:
(1) Framework Java module
The system compiles and generates the framework.jar package, which provides an upgrade call interface to the Application; interacts with the underlying Hal layer to call back

(2) AIDL interface
describes the interface definition of the upper layer and the HAL layer, and communicates between processes


(3) The main module of the HAL layer module update_engine business processing, which implements the AIDL interface to provide services. The SOC upgrade process is realized through 5 Actions, which are executed sequentially and step by step through ActionProcessor management.

The following figure is the UpdateEngine.java class diagram of the Framework layer, which mainly describes the interface provided to the application

insert image description here

The following figure is the Framework layer UpdateEngineCallback.java class diagram, which mainly describes the interface that the application needs to implement

insert image description here

The following table defines the UpdateEngine aidl interface

update_engine aidl interface definition Functional description
void applyPayload (String url, in long payload_offset, in long payload_size, in String[] headerKeyValuePairs); Call the applyPayload interface, pass in the upgrade parameters, and start the upgrade [url: upgrade package path Payload_offset: payload offset in update.zip Payload_size: payload file size headerKeyValuePairs: data in metadata]
boolean bind (IUpdateEngineCallback callback) Bind the callback, the bottom layer will inform the upper layer of the upgrade status, upgrade progress results and other information through this callback [callback: the object that implements IUpdateEngineCallback]
boolean unbind (IUpdateEngineCallback callback) Unbinding callback, corresponding to the above binding callback, unbinding [callback: the object that implements IUpdateEngineCallback]
void suspend() Pause the upgrade, the upper layer can suspend the upgrade process through this interface
void resume() Resume upgrade, the upper layer can restore the upgrade status from the pause switch through this interface
void cancel() Cancel the upgrade, the upper layer can cancel the upgrade through this interface
void resetStatus() Reset upgrade status. The upper layer resets the upgrade status through this interface
boolean verifyPayloadApplicable (in String metadataFilename) Verify whether this metadata data can be applied to this device [metadata path]

The following table defines the UpdateEngine callback interface

update_engine callback aidl interface definition Functional description
void onStatusUpdate (int status_code, float percentage) Upgrade status callback, progress callback
void onPayloadApplicationComplete (int error_code) Upgrade result callback

UpdateEngine module function flow chart:

insert image description here

The UpdateEngine registration-upgrade-callback process sequence diagram is as follows:

insert image description here

2.3 System UpdateEngine upgrade process

Overall overview: Regarding the UpdateEngine upgrade process, we plan to start from the above two key interfaces bind and applyPayload, and describe the upgrade process applyPayload and the upgrade callback process bind;

2.3.1 Upgrade process

2.3.1.1 Action mechanism

Before starting to explain the upgrade process, it is necessary for us to give an overview of how UpdateEngine manages the upgrade steps, and first understand the upgrade steps as a whole.

2.3.1.1.1 Action

In the UpdateEngine upgrade process, the entire refreshing process is logically divided into five steps, and each step is represented by an Action, which are update_boot_flags_action, install_plan_action, download_action, filesystem_verifier_action, and postinstall_runner_action.

Action definition Brief description of functions
update_boot_flags_action update_boot_flags_action.h Complete initialization of some flag variables
install_plan_action install_plan.h Build an InstallPlan structure variable and associate OutputPipe
download_action download_action.h Build http_fetcher to complete the upgrade data download, and the writer_ object of DeltaPerformer is used for data analysis and update
filesystem_verifier_action filesystem_verifier_action.h Verify the HASH values ​​​​of the partitions that need to be upgraded one by one
postinstall_runner_action postinstall_runner_action.h Execute the postinstall script on the upgraded partition, and set the partition to bootable active state after the upgrade is successful

Regarding the definition of Action, two classes are involved: AbstractAction and Action. The definitions are all under the path of /android/system/update_engine/common/action.h. Below is a class diagram of the two classes:

AbstractAction class diagram:

insert image description here

Action class diagram:

insert image description here

The AbstractAction class can be understood as the Action base class. The virtual functions defined in it, each specific action will override the virtual function methods in this class, and define the logic functions of different stages of the Action, such as start, pause, resume, stop, Complete the logic of scene functions; the Action class inherits the AbstractAction class, introduces the function of ActionPipe, and defines the input and output objects of the Action. The ActionPipe will be introduced below.

Then the Action defined in UpdateEngine should have the functions of the above two classes: functional logic and ActionPipe input and output objects. Action defined in UpdateEngine is inherited from InstallPlanAction, and InstallPlanAction is inherited from 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 ActionProcessor

Action represents the upgrade steps of UpdateEngine, so a set of mechanisms for controlling and managing Actions is required. ActionProcessor controls and manages processes such as enqueuing, starting, suspending, resuming, stopping, status judgment, Action acquisition, and operation end logic.

ActionProcessor is defined in "android/system/update_engine/common/action_processor.h".

The ActionProcessor class diagram is as follows:

insert image description here

The ActionProcessorDelegate class diagram is as follows:

insert image description here

文件: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, as an Action management class, has the following functions:

Action into the queue: EnqueueAction

Action start and stop: StartProcessing StopProcessing

Action pause and resume: SuspendProcessing ResumeProcessing

Action completion and switching: ActionComplete StartNextActionOrFinish

Set the delegate class: set_delegate

Determine whether the Action is running: IsRunning()

Determine whether the Action is suspended: suspended_

ActionProcessorDelegate, as a delegate class, is mainly used to notify ActionProcess of the status and events during processing. Its functions are as follows:

When an Action completes the processing of its function, notify ActionProcessor to call ActionCompleted()

When the stop handler is called, call ProcessingStopped()

ProcessingDone() is called when all Actions in the Action Processor are complete

2.3.1.1.3 ActionPipe

Similar to the pipeline of Unix system, in the Action mechanism, these Actions will also be linked together through the pipeline ActionPipe. The output of the previous Action will be used as the input of the next Action.

Therefore, in Update Engine, there is a sequence relationship among all Actions. For example, the FilesystemVerifierAction operation can be started only after the DownloadAction has completed the operation; and the PostinstallRunnerAction operation can only be started after the FilesystemVerifierAction is completed.

The function of the ActionPipe class is. The class is defined in "android/system/update_engine/common/action_pipe.h".

The ActionPipe class diagram is as follows:

insert image description here

// 文件: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);
};

When is the input and output object in Action completed?

Action will have InputObject and OutputObject, when and how are these objects completed?

Let me talk about the answer first: InputObject is the pipeline input object of this Action, so it should be obtained before the function of this Action is executed, and the first function executed by the Action should be the PerformAction() function, so the InputObject is generally obtained in this method ; OutputObject is the pipeline output object of this Action and also the input object of the next Action, so it should be set after the execution of the Action function is completed, and the last function executed by the Action should be the ActionComplete() function, so the OutputObject is generally set in made before this method call.

2.3.1.1.4 Summary Diagram

Generally speaking, the Action mechanism is shown in the figure below. The upgrade steps of the UpdateEngine module are represented by Action, and the input and output objects of Action are controlled by ActionPipe. All Action actions will be stored in the ActionPorcessor management class, and the ActionProcessor management class will use ActionProcessorDelegate The delegation class controls the rhythm of the overall Action operation.

insert image description here

2.3.1.2 applyPayload process

This section will start from the flow of the applyPayload function, and describe the details from class structure to function implementation.

2.3.1.2.1 BinderUpdateEngineAndroidService 类

From the process analysis of the previous UpdateEngine startup, the AIDL server object of UpdateEngine is the BinderUpdateEngineAndroidService class, and the UpdateEngine aidl server object obtained by the upper layer is actually the BinderUpdateEngineAndroidService class object. Let's look at the definition of this class:

BinderUpdateEngineAndroidService class structure diagram:

insert image description here

It can be found from the class definition that BinderUpdateEngineAndroidService inherits android::os::BnUpdateEngine and ServiceObserverInterface; android::os::BnUpdateEngine is an AIDL object, and ServiceObserverInterface encapsulates the callback interface class. That is to say, BinderUpdateEngineAndroidService is the object that receives the upper layer call and callback information to the upper layer.

// 文件: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_;
};

In fact, there is no specific implementation of AIDL interface in the implementation of BinderUpdateEngineAndroidService class. The specific implementation is to call the ApplyPayload interface of ServiceDelegateAndroidInterface class.

2.3.1.2.2 UpdateAttempterAndroid class

ServiceDelegateAndroidInterface is equivalent to an interface file. This class defines a function implementation interface based on the AIDL interface. Subsequent functional classes inherit this interface and implement such methods to provide specific functions. The subclass UpdateAttempterAndroid inherits from ServiceDelegateAndroidInterface, ActionProcessorDelegate, DownloadActionDelegate, PostinstallRunnerAction: :DelegateInterface; is the specific implementation class of the UpdateEngine function.

UpdateAttempterAndroid class structure diagram:

insert image description here

Its importance can be found from the UpdateAttempterAndroid structure. ServiceDelegateAndroidInterface is the function class for implementing the AIDL interface; DownloadActionDelegate is the function class for the Download part in the upgrade step; PostinstallRunnerAction::DelegateInterface is the function class for the PostInstall part in the upgrade step; ActionProcessorDelegate is the function class for the Action mechanism of UpdateEngine functional class;

文件: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 function implementation

Next, we enter the implementation of ApplyPayload() of UpdateAttempterAndroid and start to analyze the upgrade process

文件: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;
}

To summarize the contents of the ApplyPayload method:

1. Determine the upgrade status

2. Parse the incoming parameters

3. Set the incoming parameters to the install_plan_ structure

4. Create and upgrade various actions

5. Call back the current upgrade status to the client

6. Start the operation of Action in ActionProcessor

2.3.1.2.4 BuildUpdateActions function implementation

In the ApplyPayload() upgrade trigger interface, the process of creating Action actions is completed by BuildUpdateActions. Let's analyze the implementation process of creating Action.

文件: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 Implementation of ScheduleProcessingStart function

In the implementation of the ApplyPayload interface, the ScheduleProcessingStart() function is called to start the Action execution in the 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())));
}

Let's track how the Action is executed.

文件: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 structure analysis

As mentioned earlier, the InstallPlan structure is involved in the entire upgrade, and is the input object and output object of most Action actions.

The data in the InstallPlan structure is parsed from the upgrade package, and this structure will be continuously filled during the upgrade process, and the upgrade is finally completed.

The structure of InstallPlan is shown in the following figure:

insert image description here

 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;  // 公钥,此密钥已经内置到系统中
};

source represents the currently running system, and target represents the standby system at this time.

The source system can also be regarded as an old system, because when upgrading to detect a new version, the new version will be detected according to the source system, and when upgrading, the source system will be copied to the target first, and then the upgrade package will be used Upgrade the target system.

2.3.2 Callback process

As mentioned earlier, BinderUpdateEngineAndroidService encapsulates the implementation of aidl interface and callback. BinderUpdateEngineAndroidService inherits android::os::BnUpdateEngine and ServiceObserverInterface; android::os::BnUpdateEngine is an AIDL object, and ServiceObserverInterface encapsulates the callback interface class. Here first look at the definition of the callback method in the ServiceObserverInterface class.

文件: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 defines the callback interface. BinderUpdateEngineAndroidService inherits the ServiceObserverInterface class and provides callback implementation. Let's track the function implementation.

文件: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));
  }
}

Next: Android UpdateEngine module analysis (4) UpdateEngine upgrade logic


---------------------
Author: Yang_Mao_Shan
Source: CSDN
Original: https://blog.csdn.net/Yang_Mao_Shan/article/details/131637570
Copyright statement: This article Original article for the author, please attach the blog post link for reprint!
Content analysis By: CSDN, CNBLOG blog post one-click reprint plug-in

Guess you like

Origin blog.csdn.net/xiaowang_lj/article/details/132028660