Analyse du module Android UpdateEngine (3) Déclencheur de mise à niveau et introduction du mécanisme d'action

avant-propos

Nous avons déjà analysé le processus de compilation et de démarrage du module UpdateEngine et avons une compréhension préliminaire du module UpdateEngine. Ensuite, nous allons commencer par la fonction de mise à niveau et analyser le processus de mise à jour de UpdateEngine. Démarrer l'analyse. Il y a plusieurs étapes dans le processus de mise à jour de UpdateEngine, et chaque étape est contrôlée par une action. Par conséquent, nous expliquons d'abord le mécanisme d'action du module UpdateEngine, et décrivons la méthode de déclenchement et le processus de mise en œuvre de la mise à niveau.

Précédent : Analyse du module Android UpdateEngine (2) Démarrage du service UpdateEngine
Suivant : Analyse du module Android UpdateEngine (4) Logique de mise à niveau UpdateEngine

texte

Il existe deux manières de déclencher la mise à jour de UpdateEngine :

La première consiste à déclencher sous la forme d'un client de ligne de commande, qui est déclenché par l'outil update_engine_client dans la ligne de commande ;

La seconde est d'utiliser l'interface native fournie par Android pour déclencher.Ici, la méthode de déclenchement est basée sur la communication entre l'interface Aidl et l'UpdateEngine, et se déclenche en fonction du processus ;

1. ligne de commande update_engine_client

Lorsque vous utilisez la ligne de commande update_engine_client pour déclencher la mise à niveau, vous devez d'abord décompresser le package de mise à niveau zip du SOC et obtenir le fichier au format suivant :

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

Le format de la commande update_engine_client est :

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

Entrez ensuite le shell adb dans la ligne de commande cmd . Saisissez la commande de mise à niveau :

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"

Une fois la mise à niveau terminée, vous pouvez utiliser cat proc/cmdline pour afficher le changement de partition AB avant et après la mise à niveau et déterminer si la mise à niveau a réussi. "androidboot.slot_suffix" représente la partition en cours d'exécution, comme indiqué ci-dessous :

:/ # 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. Interface Android

Dans le code source Android, Google fournit un apk nommé SystemUpdater pour mettre à jour la démo SOC sur le disque USB local, qui peut être compris comme une application de démonstration décrivant le processus d'appel de l'interface update_engine. Ensuite, nous allons commencer avec cette application, partir du processus d'appel d'interface et analyser le processus d'utilisation de la mise à niveau de l'interface native en fonction du processus.

2.1 Appliquer SystemUpdater

2.1.1 Présentation de SystemUpdater

Le répertoire de code de l'application SystemUpdater est : android/packages/apps/Car/SystemUpdater

Commande de démarrage de l'application : adb shell am start -n com.android.car.systemupdater.SystemUpdaterActivity

Les fonctions principales sont :

Lisez le fichier de mise à niveau sur le disque U et l'utilisateur clique sur le fichier de mise à niveau cible

Enregistrez la progression de la mise à niveau UpdateEngine et le rappel des résultats, appelez l'interface de mise à niveau UpdateEngine pour transmettre les paramètres de mise à niveau afin de déclencher la mise à niveau

​ Demander à powermanager de redémarrer la machine après la mise à niveau

Les fichiers de code sont :

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

2.2.2 Processus clé SystemUpdater

Voici le chronogramme de l'appel SystemUpdater :

insérez la description de l'image ici

Pour la mise à niveau, deux étapes sont nécessaires, la première consiste à enregistrer le rappel de la progression et du résultat de la mise à niveau ; la seconde consiste à déclencher la mise à niveau.

Ce qui suit fait partie du code de SystemUpdater lié à la mise à niveau :


/** 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 Architecture du moteur de mise à jour

La figure suivante est le schéma d'architecture de UpdateEngine

insérez la description de l'image ici

Description de la structure du module UpdateEngine :
(1) Module Framework Java
Le système compile et génère le package framework.jar, qui fournit une interface d'appel de mise à niveau à l'application ; interagit avec la couche Hal sous-jacente pour rappeler

(2) L'interface AIDL
décrit la définition de l'interface de la couche supérieure et de la couche HAL, et communique entre les processus


(3) Le module principal du module de couche HAL update_engine business processing, qui implémente l'interface AIDL pour fournir des services. Le processus de mise à niveau du SOC est réalisé à travers 5 actions, qui sont exécutées séquentiellement et étape par étape via la gestion d'ActionProcessor.

La figure suivante est le diagramme de classes UpdateEngine.java de la couche Framework, qui décrit principalement l'interface fournie à l'application

insérez la description de l'image ici

La figure suivante est le diagramme de classes UpdateEngineCallback.java de la couche Framework, qui décrit principalement l'interface que l'application doit implémenter

insérez la description de l'image ici

Le tableau suivant définit l'interface d'aide UpdateEngine

update_engine aidl définition de l'interface Mode d'emploi
void applyPayload (URL de chaîne, en long payload_offset, en long payload_size, en String [] headerKeyValuePairs); Appelez l'interface applyPayload, transmettez les paramètres de mise à niveau et démarrez la mise à niveau [url : chemin du package de mise à niveau Payload_offset : décalage de la charge utile dans update.zip Payload_size : taille du fichier de charge utile headerKeyValuePairs : données dans les métadonnées]
liaison booléenne (rappel IUpdateEngineCallback) Liez le rappel, la couche inférieure informera la couche supérieure de l'état de la mise à niveau, des résultats de la progression de la mise à niveau et d'autres informations via ce rappel [rappel : l'objet qui implémente IUpdateEngineCallback]
boolean unbind (rappel IUpdateEngineCallback) Rappel déliant, correspondant au rappel de liaison ci-dessus, déliant [rappel : l'objet qui implémente IUpdateEngineCallback]
annuler la suspension () Suspendez la mise à niveau, la couche supérieure peut suspendre le processus de mise à niveau via cette interface
annuler le CV() Reprendre la mise à niveau, la couche supérieure peut restaurer l'état de la mise à niveau à partir du commutateur de pause via cette interface
annuler annuler() Annuler la mise à niveau, la couche supérieure peut annuler la mise à niveau via cette interface
annuler resetStatus() Réinitialiser l'état de la mise à niveau. La couche supérieure réinitialise l'état de la mise à niveau via cette interface
boolean verifyPayloadApplicable (dans String metadataFilename) Vérifiez si ces données de métadonnées peuvent être appliquées à cet appareil [chemin des métadonnées]

Le tableau suivant définit l'interface de rappel UpdateEngine

définition de l'interface d'aide au rappel update_engine Mode d'emploi
void onStatusUpdate (int status_code, pourcentage flottant) Rappel d'état de mise à niveau, rappel de progression
void onPayloadApplicationComplete (int error_code) Rappel du résultat de la mise à niveau

Organigramme des fonctions du module UpdateEngine :

insérez la description de l'image ici

Le diagramme de séquence du processus d'enregistrement-mise à niveau-rappel d'UpdateEngine est le suivant :

insérez la description de l'image ici

2.3 Processus de mise à niveau du moteur de mise à jour du système

Présentation générale : en ce qui concerne le processus de mise à niveau UpdateEngine, nous prévoyons de commencer à partir des deux interfaces clés ci-dessus bind et applyPayload, et de décrire le processus de mise à niveau applyPayload et le processus de rappel de mise à niveau bind ;

2.3.1 Processus de mise à niveau

2.3.1.1 Mécanisme d'action

Avant de commencer à expliquer le processus de mise à niveau, il est nécessaire pour nous de donner un aperçu de la façon dont UpdateEngine gère les étapes de mise à niveau et de comprendre d'abord les étapes de mise à niveau dans leur ensemble.

2.3.1.1.1 Action

Dans le processus de mise à niveau UpdateEngine, l'ensemble du processus d'actualisation est logiquement divisé en cinq étapes, et chaque étape est représentée par une action, qui sont update_boot_flags_action, install_plan_action, download_action, filesystem_verifier_action et postinstall_runner_action.

Action définition Brève description des fonctions
update_boot_flags_action update_boot_flags_action.h Initialisation complète de certaines variables flag
install_plan_action install_plan.h Construire une variable de structure InstallPlan et associer OutputPipe
download_action download_action.h Construisez http_fetcher pour terminer le téléchargement des données de mise à niveau, et l'objet writer_ de DeltaPerformer est utilisé pour l'analyse et la mise à jour des données
filesystem_verifier_action filesystem_verifier_action.h Vérifiez les valeurs HASH ​​​​des partitions qui doivent être mises à niveau une par une
postinstall_runner_action postinstall_runner_action.h Exécutez le script de post-installation sur la partition mise à niveau et définissez la partition sur l'état actif amorçable une fois la mise à niveau réussie

Concernant la définition d'Action, deux classes sont impliquées : AbstractAction et Action. Les définitions sont toutes sous le chemin de /android/system/update_engine/common/action.h. Ci-dessous un diagramme de classes des deux classes :

Diagramme de classes AbstractAction :

insérez la description de l'image ici

Diagramme de classe d'action :

insérez la description de l'image ici

La classe AbstractAction peut être comprise comme la classe de base Action. Les fonctions virtuelles qui y sont définies, chaque action spécifique remplacera les méthodes de fonctions virtuelles de cette classe et définira les fonctions logiques des différentes étapes de l'action, telles que start, pause, reprendre, arrêter, compléter la logique des fonctions de scène ; la classe Action hérite de la classe AbstractAction, introduit la fonction d'ActionPipe et définit les objets d'entrée et de sortie de l'Action. L'ActionPipe sera présenté ci-dessous.

Ensuite, l'action définie dans UpdateEngine doit avoir les fonctions des deux classes ci-dessus : la logique fonctionnelle et les objets d'entrée et de sortie ActionPipe. L'action définie dans UpdateEngine est héritée de InstallPlanAction et InstallPlanAction est héritée de 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 ActionProcesseur

L'action représente les étapes de mise à niveau de UpdateEngine, donc un ensemble de mécanismes de contrôle et de gestion des actions est requis. ActionProcessor contrôle et gère les processus tels que la mise en file d'attente, le démarrage, la suspension, la reprise, l'arrêt, le jugement d'état, l'acquisition d'action et la logique de fin d'opération.

ActionProcessor est défini dans "android/system/update_engine/common/action_processor.h".

Le diagramme de classes ActionProcessor est le suivant :

insérez la description de l'image ici

Le diagramme de classes ActionProcessorDelegate est le suivant :

insérez la description de l'image ici

文件: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, en tant que classe de gestion d'action, a les fonctions suivantes :

Action dans la file d'attente : EnqueueAction

Démarrage et arrêt de l'action : StartProcessing StopProcessing

Pause et reprise de l'action : SuspendProcessing ResumeProcessing

Achèvement et changement d'action : ActionComplete StartNextActionOrFinish

Définissez la classe déléguée : set_delegate

Déterminez si l'action est en cours d'exécution : IsRunning()

Déterminez si l'action est suspendue : suspend_

ActionProcessorDelegate, en tant que classe déléguée, est principalement utilisée pour notifier à ActionProcess l'état et les événements pendant le traitement. Ses fonctions sont les suivantes :

Lorsqu'une action termine le traitement de sa fonction, notifiez ActionProcessor pour appeler ActionCompleted()

Lorsque le gestionnaire d'arrêt est appelé, appelez ProcessingStopped()

ProcessingDone() est appelé lorsque toutes les actions du processeur d'action sont terminées

2.3.1.1.3 Pipe d'action

Semblable au pipeline du système Unix, dans le mécanisme d'action, ces actions seront également liées entre elles via le pipeline ActionPipe. La sortie de l'action précédente sera utilisée comme entrée de l'action suivante.

Par conséquent, dans Update Engine, il existe une relation de séquence entre toutes les actions. Par exemple, l'opération FilesystemVerifierAction ne peut être démarrée qu'une fois que DownloadAction a terminé l'opération et l'opération PostinstallRunnerAction ne peut être démarrée qu'une fois que FilesystemVerifierAction est terminée.

La fonction de la classe ActionPipe est. La classe est définie dans "android/system/update_engine/common/action_pipe.h".

Le diagramme de classes ActionPipe est le suivant :

insérez la description de l'image ici

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

Quand l'objet d'entrée et de sortie dans Action est-il terminé ?

L'action aura InputObject et OutputObject, quand et comment ces objets sont-ils complétés ?

Permettez-moi de parler d'abord de la réponse : InputObject est l'objet d'entrée du pipeline de cette action, il doit donc être obtenu avant que la fonction de cette action ne soit exécutée, et la première fonction exécutée par l'action doit être la fonction PerformAction(), donc le InputObject est généralement obtenu dans cette méthode ; OutputObject est l'objet de sortie du pipeline de cette action et également l'objet d'entrée de l'action suivante, il doit donc être défini une fois l'exécution de la fonction d'action terminée et la dernière fonction exécutée par l'action doit être la fonction ActionComplete(), de sorte que OutputObject est généralement défini avant cet appel de méthode.

2.3.1.1.4 Schéma récapitulatif

D'une manière générale, le mécanisme Action est illustré dans la figure ci-dessous. Les étapes de mise à niveau du module UpdateEngine sont représentées par Action, et les objets d'entrée et de sortie d'Action sont contrôlés par ActionPipe. Toutes les actions Action seront stockées dans la classe de gestion ActionPorcessor, et la classe de gestion ActionProcessor utilisera ActionProcessorDelegate La classe de délégation contrôle le rythme de l'opération Action globale.

insérez la description de l'image ici

2.3.1.2 processus applyPayload

Cette section commencera par le flux de la fonction applyPayload et décrira les détails de la structure de classe à l'implémentation de la fonction.

2.3.1.2.1 BinderUpdateEngineAndroidService 类

D'après l'analyse de processus du démarrage précédent d'UpdateEngine, l'objet serveur AIDL d'UpdateEngine est la classe BinderUpdateEngineAndroidService, et l'objet serveur d'aide UpdateEngine obtenu par la couche supérieure est en fait l'objet de classe BinderUpdateEngineAndroidService. Regardons la définition de cette classe :

Diagramme de structure de la classe BinderUpdateEngineAndroidService :

insérez la description de l'image ici

Il peut être trouvé à partir de la définition de classe que BinderUpdateEngineAndroidService hérite d'Android :: os :: BnUpdateEngine et ServiceObserverInterface ; android :: os :: BnUpdateEngine est un objet AIDL et ServiceObserverInterface encapsule la classe d'interface de rappel. C'est-à-dire que BinderUpdateEngineAndroidService est l'objet qui reçoit les informations d'appel et de rappel de la couche supérieure vers la couche supérieure.

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

En fait, il n'y a pas d'implémentation spécifique de l'interface AIDL dans l'implémentation de la classe BinderUpdateEngineAndroidService.L'implémentation spécifique consiste à appeler l'interface ApplyPayload de la classe ServiceDelegateAndroidInterface.

2.3.1.2.2 Classe UpdateAttempterAndroid

ServiceDelegateAndroidInterface équivaut à un fichier d'interface. Cette classe définit une interface d'implémentation de fonction basée sur l'interface AIDL. Les classes fonctionnelles suivantes héritent de cette interface et implémentent ces méthodes pour fournir des fonctions spécifiques. La sous-classe UpdateAttempterAndroid hérite de ServiceDelegateAndroidInterface, ActionProcessorDelegate, DownloadActionDelegate, PostinstallRunnerAction : : DelegateInterface; est la classe d'implémentation spécifique de la fonction UpdateEngine.

Diagramme de structure de la classe UpdateAttempterAndroid :

insérez la description de l'image ici

Son importance peut être trouvée à partir de la structure UpdateAttempterAndroid. ServiceDelegateAndroidInterface est la classe de fonction pour l'implémentation de l'interface AIDL ; DownloadActionDelegate est la classe de fonction pour la partie Download dans l'étape de mise à niveau ; PostinstallRunnerAction::DelegateInterface est la classe de fonction pour la partie PostInstall dans la mise à niveau. étape ; ActionProcessorDelegate est la classe de fonctions du mécanisme d'action de la classe fonctionnelle UpdateEngine ;

文件: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 Implémentation de la fonction ApplyPayload

Ensuite, nous entrons dans l'implémentation de ApplyPayload() de UpdateAttempterAndroid et commençons à analyser le processus de mise à niveau

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

Pour résumer le contenu de la méthode ApplyPayload :

1. Déterminer l'état de la mise à niveau

2. Analyser les paramètres entrants

3. Définissez les paramètres entrants sur la structure install_plan_

4. Créer et mettre à jour diverses actions

5. Rappeler l'état actuel de la mise à niveau au client

6. Démarrer l'opération d'action dans ActionProcessor

2.3.1.2.4 Implémentation de la fonction BuildUpdateActions

Dans l'interface du déclencheur de mise à niveau ApplyPayload(), le processus de création d'actions Action est complété par BuildUpdateActions. Analysons le processus de mise en œuvre de la création d'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 Implémentation de la fonction ScheduleProcessingStart

Dans l'implémentation de l'interface ApplyPayload, la fonction ScheduleProcessingStart() est appelée pour démarrer l'exécution de l'action dans l'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())));
}

Suivons comment l'action est exécutée.

文件: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 Analyse de la structure InstallPlan

Comme mentionné précédemment, la structure InstallPlan est impliquée dans l'ensemble de la mise à niveau et constitue l'objet d'entrée et l'objet de sortie de la plupart des actions Action.

Les données de la structure InstallPlan sont analysées à partir du package de mise à niveau, et cette structure sera remplie en continu pendant le processus de mise à niveau, et la mise à niveau est finalement terminée.

La structure d'InstallPlan est illustrée dans la figure suivante :

insérez la description de l'image ici

 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 représente le système en cours d'exécution et cible représente le système de secours à ce moment.

Le système source peut également être considéré comme un ancien système, car lors de la mise à niveau pour détecter une nouvelle version, la nouvelle version sera détectée en fonction du système source, et lors de la mise à niveau, le système source sera d'abord copié sur la cible, puis le package de mise à niveau sera utilisé Mettez à niveau le système cible.

2.3.2 Processus de rappel

Comme mentionné précédemment, BinderUpdateEngineAndroidService encapsule l'implémentation de l'interface et du rappel aidl. BinderUpdateEngineAndroidService hérite d'Android :: os :: BnUpdateEngine et ServiceObserverInterface ; android :: os :: BnUpdateEngine est un objet AIDL et ServiceObserverInterface encapsule la classe d'interface de rappel. Ici, regardez d'abord la définition de la méthode de rappel dans la classe 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 définit l'interface de rappel. BinderUpdateEngineAndroidService hérite de la classe ServiceObserverInterface et fournit l'implémentation de rappel. Suivons l'implémentation de la fonction.

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

Suivant : Analyse du module Android UpdateEngine (4) Logique de mise à jour UpdateEngine


---------------------
Auteur : Yang_Mao_Shan
Source : CSDN
Original : https://blog.csdn.net/Yang_Mao_Shan/article/details/131637570
Déclaration de copyright : Cette article Article original pour l'auteur, veuillez joindre le lien du blog pour réimpression !
Analyse de contenu Par : CSDN, blog CNBLOG, plug-in de réimpression en un clic

Je suppose que tu aimes

Origine blog.csdn.net/xiaowang_lj/article/details/132028660
conseillé
Classement