A/B系统是Android设计给OTA用,前面有文章分析过,只不过是LK下。现在看下QCOM UEFI下对A/B retry count是否递减的逻辑。

EFI_STATUS
FindBootableSlot (Slot *BootableSlot)
{
  Unbootable = (BootEntry->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) >>
               PART_ATT_UNBOOTABLE_BIT;
  BootSuccess = (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) >>
                PART_ATT_SUCCESS_BIT;
  RetryCount =
      (BootEntry->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >>
      PART_ATT_MAX_RETRY_CNT_BIT;

  if (Unbootable == 0 && BootSuccess == 1) {
    DEBUG (
        (EFI_D_VERBOSE, "Active Slot %s is bootable\n", BootableSlot->Suffix));
  } else if (Unbootable == 0 && BootSuccess == 0 && RetryCount > 0) {
    if ((!IsABRetryCountDisabled () &&
        !IsBootDevImage ()) &&
      IsABRetryCountUpdateRequired ()
      ){
      RetryCount--; //tj: here
      BootEntry->PartEntry.Attributes &= ~PART_ATT_MAX_RETRY_COUNT_VAL;
      BootEntry->PartEntry.Attributes |= RetryCount
                                         << PART_ATT_MAX_RETRY_CNT_BIT;
      UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
      DEBUG ((EFI_D_INFO, "Active Slot %s is bootable, retry count %ld\n",
              BootableSlot->Suffix, RetryCount));
    } else {
      DEBUG ((EFI_D_INFO, "A/B retry count NOT decremented\n"));
    }
  } else {
    DEBUG ((EFI_D_INFO, "Slot %s is unbootable, trying alternate slot\n",
            BootableSlot->Suffix));
    GUARD_OUT (HandleActiveSlotUnbootable ());
  }

可以看到,如果当前槽是可以启动的(Unbootable == 0)而且成功起来过(BootSuccess == 1)就直接启动了,一般都是非第一次系统启动。

如果可以启动但是没有成功起来过(比如刚刷完机)启动次数还有时:

case1: 如果A/B次数被禁用了,就不减,有个feature宏控制。

#ifdef AB_RETRYCOUNT_DISABLE
BOOLEAN IsABRetryCountDisabled (VOID)
{
  return TRUE;
}
#else
BOOLEAN IsABRetryCountDisabled (VOID)
{
  return FALSE;
}
#endif

case2: 如果是IsBootDevImage(),也不减。

BOOLEAN IsBootDevImage (VOID)
{
  return BootDevImage;
}
EFI_STATUS
BootLinux (BootInfo *Info)
{
  ...
  if (AsciiStrStr (BootParamlistPtr.CmdLine, "root=")) {
    BootDevImage = TRUE;
  }

应该是cmdline带了root=,有个提交:

commit 6a54fe1c4a886ea1560fe617dfc975776d3edf97
Author: Channagoud Kadabi <ckadabi@codeaurora.org>
Date:   Fri Jun 2 17:00:56 2017 -0700

    QcommodulePkg: BootLib: do no decrement retry count on dev images

    Dev images with custom userspace/ramdisk do not have slot successful
    set, do not decrement retry count for such custom images.

    Change-Id: Ia37e853b40b41bb62c766838d6a7efc4b37f4427

一般不用。

case3: if no case1而且no case2,我们根据boot into mode来决定是否递减。

也就是IsABRetryCountUpdateRequired():

BOOLEAN IsABRetryCountUpdateRequired (VOID)
{
  BOOLEAN BatteryStatus;

  /* Check power off charging */
  TargetPauseForBatteryCharge (&BatteryStatus);

  /* Do not decrement bootable retry count in below states:
     * fastboot, fastbootd, charger, recovery
     */
  if ((BatteryStatus &&
       IsChargingScreenEnable ()) ||
       BootIntoFastboot ||
       BootIntoRecovery) {
    return FALSE;
  }
  return TRUE;
}

注释写的很清楚了,fastboot/fastbootd/charger/recovery state不减。

note that IsChargingScreenEnable()

提下fastbootd是userspace fastboot,是dynamic partition(动态分区,Android Q引入)里的东东。

Done.