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.