一个关于VTS VtsKernelCheckpointTest、VtsKernelCheckpointTest测项失败的代码分析

如刚才实验,烧录GSI之后,本来已经被格式化为ext4的metadata分区,又被格式化为无格式的分区。

我这边继续Check发现,在替换GSI的SOP中,fastboot –w选项如果在bootloader执行,会清userdata、cache、metadata分区为无格式分区,而后进入recovery再次格式化成ext4。

FLOW如下:

a. fastboot程序-w选项如果在loader中执行会传命令给loader清userdata,cache,metadata分区

https://android.googlesource.com/platform/system/core/+/refs/heads/master/fastboot/fastboot.cpp

    if (wants_wipe) {
        if (force_flash) {
            CancelSnapshotIfNeeded();
        }
        std::vector<std::string> partitions = { "userdata", "cache", "metadata" };
        for (const auto& partition : partitions) {
            std::string partition_type;
            if (fb->GetVar("partition-type:" + partition, &partition_type) != fastboot::SUCCESS) {
                continue;
            }
            if (partition_type.empty()) continue;
            fb->Erase(partition);
            if (partition == "userdata" && set_fbe_marker) {
                fprintf(stderr, "setting FBE marker on initial userdata...\n");
                std::string initial_userdata_dir = create_fbemarker_tmpdir();
                fb_perform_format(partition, 1, partition_type, "", initial_userdata_dir, fs_options);
                delete_fbemarker_tmpdir(initial_userdata_dir);
            } else {
                fb_perform_format(partition, 1, partition_type, "", "", fs_options);
            }
        }
    }

 

b. bootloader根据fastboot传下的分区列表清除对应分区。

 

c. recovery收到wipe=data会格式化userdata,cache,metadata分区为ext4格式.

https://android.googlesource.com/platform/bootable/recovery/+/refs/heads/master/recovery.cpp

      case Device::WIPE_DATA:
        save_current_log = true;
        if (ui->IsTextVisible()) {
          if (ask_to_wipe_data(device)) {
            WipeData(device, false);
          }
        } else {
          WipeData(device, false);
          return Device::NO_ACTION;
        }
        break;

 

但是目前的情况是做完fastboot –w选项之后,发现userdata,cache都被格式化为ext4格式,而metadata分区未被格式化,所以猜想recovery没有格式化metadata,

进一步看code可以看到,recovery中如果要格式化metadata,需要volume_for_mount_point返回非空指针,

https://android.googlesource.com/platform/bootable/recovery/+/refs/heads/master/install/wipe_data.cpp

bool WipeData(Device* device, bool convert_fbe) {
  RecoveryUI* ui = device->GetUI();
  ui->Print("\n-- Wiping data...\n");
  if (!FinishPendingSnapshotMerges(device)) {
    ui->Print("Unable to check update status or complete merge, cannot wipe partitions.\n");
    return false;
  }
  bool success = device->PreWipeData();
  if (success) {
    success &= EraseVolume(DATA_ROOT, ui, convert_fbe);
    bool has_cache = volume_for_mount_point("/cache") != nullptr;
    if (has_cache) {
      success &= EraseVolume(CACHE_ROOT, ui, false);
    }
    if (volume_for_mount_point(METADATA_ROOT) != nullptr) {
      success &= EraseVolume(METADATA_ROOT, ui, false);
    }
  }
  if (success) {
    success &= device->PostWipeData();
  }
  ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
  return success;
}

 

而volume_for_mount_point调用GetEntryForMountPoint,根据entry.mount_point判断METADATA是否存在,如果存在就返回METADATA的挂载路径,

然后EraseVolume函数会umount设备,再调用wipe_block_device清数据以及调用/system/bin/mke2fs格式化。

https://android.googlesource.com/platform/bootable/recovery/+/refs/heads/master/install/wipe_data.cpp

static bool EraseVolume(const char* volume, RecoveryUI* ui, bool convert_fbe) {
  bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
  bool is_data = (strcmp(volume, DATA_ROOT) == 0);
  ui->SetBackground(RecoveryUI::ERASING);
  ui->SetProgressType(RecoveryUI::INDETERMINATE);
  std::vector<saved_log_file> log_files;
  if (is_cache) {
    // If we're reformatting /cache, we load any past logs (i.e. "/cache/recovery/last_*") and the
    // current log ("/cache/recovery/log") into memory, so we can restore them after the reformat.
    log_files = ReadLogFilesToMemory();
  }
  ui->Print("Formatting %s...\n", volume);
  ensure_path_unmounted(volume);
  int result;
  if (is_data && convert_fbe) {
    constexpr const char* CONVERT_FBE_DIR = "/tmp/convert_fbe";
    constexpr const char* CONVERT_FBE_FILE = "/tmp/convert_fbe/convert_fbe";
    // Create convert_fbe breadcrumb file to signal init to convert to file based encryption, not
    // full disk encryption.
    if (mkdir(CONVERT_FBE_DIR, 0700) != 0) {
      PLOG(ERROR) << "Failed to mkdir " << CONVERT_FBE_DIR;
      return false;
    }
    FILE* f = fopen(CONVERT_FBE_FILE, "wbe");
    if (!f) {
      PLOG(ERROR) << "Failed to convert to file encryption";
      return false;
    }
    fclose(f);
    result = format_volume(volume, CONVERT_FBE_DIR);
    remove(CONVERT_FBE_FILE);
    rmdir(CONVERT_FBE_DIR);
  } else {
    result = format_volume(volume);
  }
  if (is_cache) {
    RestoreLogFilesAfterFormat(log_files);
  }
  return (result == 0);
}

 

因为目前看到metadata未被格式化,因此有可能类entry中没有metadata分区相关信息,所以继续查找entry的fstab如何获取的,

在fs_mgr_fstab.cpp中可以看到if(access(/system/bin/recovery, F_OK))表示当前是recovery启动,则读取recovery.fstab作为default_fstab_path。

https://android.googlesource.com/platform/system/core/+/refs/heads/master/fs_mgr/fs_mgr_fstab.cpp

// Loads the fstab file and combines with fstab entries passed in from device tree.
bool ReadDefaultFstab(Fstab* fstab) {
    Fstab dt_fstab;
    ReadFstabFromDt(&dt_fstab, false);
    *fstab = std::move(dt_fstab);
    std::string default_fstab_path;
    // Use different fstab paths for normal boot and recovery boot, respectively
    if (access("/system/bin/recovery", F_OK) == 0) {
        default_fstab_path = "/etc/recovery.fstab";
    } else {  // normal boot
        default_fstab_path = GetFstabPath();
    }
    Fstab default_fstab;
    if (!default_fstab_path.empty()) {
        ReadFstabFromFile(default_fstab_path, &default_fstab);
    } else {
        LINFO << __FUNCTION__ << "(): failed to find device default fstab";
    }
    for (auto&& entry : default_fstab) {
        fstab->emplace_back(std::move(entry));
    }
    return !fstab->empty();
}

 

如果需要Check一下recovery.fstab中的内容,因为recovery.fstab是从在AN目录下打包过去的,所以在device下看到recovery有3张fstab,检查发现,3张表都是没有metadata分区的。

所以要看一下这里加上metadata后是否可以。

上一篇:Android OTA升级详细流程分析(non-AB)


下一篇:recovery.sh