Android UpdateEngine 模块分析(三)升级触发以及Action机制介绍

前言

前面分析了 UpdateEngine 模块的编译和启动流程,对于 UpdateEngine 模块已经有了初步的了解,接下来我们从升级的功能出发,分析 UpdateEngine 的升级过程,升级过程的内容非常的多,准备从 UpdateEngine 的 Action 机制开始分析,UpdateEngine 的升级过程有很多步骤,每一个步骤由一个 Action 去控制。因此,我们先说明 UpdateEngine 模块的 Action 机制,并从升级的触发方式以及实现流程展开描述。

上一篇:Android UpdateEngine 模块分析(二)UpdateEngine 服务启动
下一篇:Android UpdateEngine 模块分析(四)UpdateEngine 升级逻辑

正文

关于 UpdateEngine 的升级有两种方式触发:

第一种是采用命令行客户端的形式触发,此种触发方式在命令行中通过 update_engine_client 工具触发;

第二种是采用 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 shell。输入升级命令:

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 提供了一个名为 SystemUpdater 的 apk 用以本地 U盘升级 SOC 的 Demo,可以理解为描述 update_engine 接口调用流程的 Demo 应用。我们接下来将从这个应用入手,从接口调用流程上出发,按流程分析使用原生接口升级的流程。

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 调用的时序图:

在这里插入图片描述

对于升级来说,有两个步骤是必须的,第一个是注册升级进度、结果的回调;第二个是触发升级。

下面是 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) Framework Java模块
系统编译生成framework.jar包,向Application提供升级调用接口;和底层Hal层进行交互回调

(2) AIDL接口
描述上层和HAL层的接口定义,进行进程间通信

(3) HAL层模块
update_engine业务处理的主要模块,实现AIDL接口提供服务。将SOC升级过程通过5个Action实现,通过ActionProcessor管理按序分步线性执行。

下图为 Framework 层 UpdateEngine.java 类图,主要描述给应用提供的接口

在这里插入图片描述

下图为 Framework 层 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:payload在update.zip中的偏移量 Payload_size:payload文件的大小 headerKeyValuePairs:metadata中的数据】
boolean bind (IUpdateEngineCallback callback) 绑定回调,底层会将升级状态,升级进度结果等信息通过此回调告诉上层 【callback:实现IUpdateEngineCallback的对象】
boolean unbind (IUpdateEngineCallback callback) 解绑回调,与上述绑定回调对应,解除绑定 【callback:实现IUpdateEngineCallback的对象】
void suspend() 暂停升级,上层可以通过此接口将升级流程暂停
void resume() 恢复升级,上层可以通过此接口将升级状态由暂停切换恢复
void cancel() 取消升级,上层可以通过此接口取消升级
void resetStatus() 重设升级状态。上层通过此接口重设升级状态
boolean verifyPayloadApplicable (in String metadataFilename) 验证此metadata数据是否能够应用在此设备中 【metadata的路径】

下表为 UpdateEngine 回调接口定义

update_engine callback aidl接口定义 功能描述
void onStatusUpdate (int status_code, float percentage) 升级状态回调、进度回调
void onPayloadApplicationComplete (int error_code) 升级结果回调

UpdateEngine 模块功能流转流程图:

在这里插入图片描述

UpdateEngine 注册-升级-回调流程序列图如下:

在这里插入图片描述

2.3 系统 UpdateEngine 升级流程

整体概述:关于 UpdateEngine 升级流程,准备从上述两个关键接口 bind 和 applyPayload 出发,从升级流程 applyPayload 以及 升级回调流程 bind 两大块展开描述;

2.3.1 升级流程

2.3.1.1 Action 机制

在开始讲解升级流程之前,我们有必要先来概述一下 UpdateEngine 对于升级的步骤是怎么管理的,先从整体去了解升级的步骤。

2.3.1.1.1 Action

在 UpdateEngine 升级流程中,将整个刷新过程按逻辑分为了 5 个步骤,每个步骤用一个 Action 来表示,分别为 update_boot_flags_action、install_plan_action、download_action、filesystem_verifier_action、postinstall_runner_action。

Action 定义 功能简述
update_boot_flags_action update_boot_flags_action.h 完成一些标志变量的初始化
install_plan_action install_plan.h 构建一个 InstallPlan 结构体变量,并关联 OutputPipe
download_action download_action.h 构建 http_fetcher 完成升级数据下载,DeltaPerformer 的 writer_ 对象用于数据的解析更新
filesystem_verifier_action filesystem_verifier_action.h 逐个校验需要升级分区的 HASH 值
postinstall_runner_action postinstall_runner_action.h 对升级后的分区执行 postinstall 脚本,并将升级成功后的分区设置为可启动 active 状态

关于 Action 的定义,涉及两个类:AbstractAction、Action。定义均在 /android/system/update_engine/common/action.h 路径下。下面是两个类的类图:

AbstractAction 类图:

在这里插入图片描述

Action 类图:

在这里插入图片描述

AbstractAction 类可以理解为是 Action 基类,其中定义的虚函数,每个具体的 action 都会重写该类中的虚函数方法,定义了 Action 不同阶段的逻辑功能,例如开始、暂停、恢复、停止、完成等场景功能逻辑;Action 类继承了 AbstractAction 类,引入了 ActionPipe 的功能,定义的则是 Action 的输入对象和输出对象,关于 ActionPipe 会在下面介绍。

那么在 UpdateEngine 中定义的 Action 应该都具备以上里两个类的功能:功能逻辑和 ActionPipe 输入输出对象。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 ActionProcessor

Action 表示 UpdateEngine 的升级步骤,那么就需要控制管理 Action 的一套机制,ActionProcessor 则是控制管理 Action 入队、开始、暂停、恢复、停止、状态判断、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 管理类,其功能如下:

Action 入队:EnqueueAction

Action 启动与停止:StartProcessing StopProcessing

Action 暂停与恢复:SuspendProcessing ResumeProcessing

Action 完成与切换:ActionComplete StartNextActionOrFinish

设置委托类:set_delegate

判断 Action 是否正在运行:IsRunning()

判断 Action 是否暂停状态:suspended_

ActionProcessorDelegate 作为一个委托类,主要用于通知 ActionProcess 处理过程中的状态和发生的事件,其功能如下:

当某个 Action 完成其功能的处理时,通知 ActionProcessor 调用 ActionCompleted()

当调用停止处理函数时,调用 ProcessingStopped()

当操作处理器中所有的 Action 都完成时,调用 ProcessingDone()

2.3.1.1.3 ActionPipe

类似于 Unix 系统的管道,Action 机制中,也会通过管道 ActionPipe 将这些 Action 链接在一起。上一个 Action 的输出会作为下一个 Action 的输入。

因此在 Update Engine 中,所有的 Action 之间有一个先后关系。例如,只有 DownloadAction 完成操作了,才能开始 FilesystemVerifierAction 操作;也只有 FilesystemVerifierAction 结束了,才会开始 PostinstallRunnerAction 操作。

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 是本 Action 的管道输入对象,那么就应该在本 Action 功能执行之前获取,而 Action 执行的第一个函数应该是 PerformAction() 函数,因此一般获取 InputObject 是在此方法中进行的;OutputObject 是本 Action 的管道输出对象,也是下一个 Action 的输入对象,那么就应该在本 Action 功能执行结束之后设置,而 Action 执行的最后一个函数应该是 ActionComplete() 函数,因此一般设置 OutputObject 是在此方法调用之前进行的。

2.3.1.1.4 总结图示

关于 Action 机制总的来说如下图所示,UpdateEngine 模块的升级步骤用 Action 来表示,Action 的输入输出对象由 ActionPipe 来控制,所有的 Action 动作会存储在 ActionPorcessor 管理类中,ActionProcessor 管理类会使用 ActionProcessorDelegate 委托类来控制整体 Action 运行的节奏。

在这里插入图片描述

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 是升级步骤中 Download 部分的功能类;PostinstallRunnerAction::DelegateInterface 是升级步骤中 PostInstall 部分的功能类;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、创建升级的各种 action

5、回调给客户端当前的升级状态

6、开启 ActionProcessor 中 Action 的运行

2.3.1.2.4 BuildUpdateActions 函数实现

在 ApplyPayload() 升级触发接口中,创建 Action 动作的过程由 BuildUpdateActions 完成。下面我们来分析下创建 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 ScheduleProcessingStart 函数实现

在 ApplyPayload 接口实现中,调用了 ScheduleProcessingStart() 函数去开启 ActionProcessor 中的 Action 执行。

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

我们来跟踪下是如何进行 Action 执行的。

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

source 代表的是现在正在运行的系统,target 代表此时备用的系统。

也可以把 source 系统作为一个旧的系统,因为在升级检测新版本的时候,会根据 source 系统检测新的版本,而在升级的时候,先会把 source 系统拷贝到 target 中,之后再利用升级包对 target 系统进行升级。

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 模块分析(四)UpdateEngine 升级逻辑


---------------------
作者:Yang_Mao_Shan
来源:CSDN
原文:https://blog.csdn.net/Yang_Mao_Shan/article/details/131637570
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件

猜你喜欢

转载自blog.csdn.net/xiaowang_lj/article/details/132028660