参考高通平台Android 10,刷机时发现刷了metadata.img,不刷userdata.img,起不来。

我们来看下这个分区的由来:

metadata: The metadata partition is used when device is encrypted and is 16MB or larger.

官方的定义如上,设备加密时使用。设备加密有2种:

Android has two methods for device encryption: file-based encryption and full-disk encryption.

file-based是Android 10及以上使用:

Note: Devices running Androi2d 7.0–9 support full-disk encryption. New devices running Android 10 and higher must use file-based encryption.

file-based加密(FBE)仅仅加密的是文件内容和文件名,其他的信息比如文件大小,权限啥的都没有加密,这些东东就是filesystem metadata。

When FBE is used, other information, such as directory layouts, file sizes, permissions, and creation/modification times, is not encrypted. Collectively, this is known as filesystem metadata.

另外,metadata加密需要硬件支持。

Android 9 introduces support for metadata encryption where hardware support is present.

这个硬件特性叫inline crypto engine

To support metadata encryption currently, your hardware needs to support an inline crypto engine

ok。

这个分区里面放的是啥?来看:

With metadata encryption, a single key present at boot time encrypts whatever content is not encrypted by FBE. This key is protected by Keymaster, which in turn is protected by verified boot.

Because nothing in the userdata partition can be read until the metadata encryption key is present, the partition table must set aside a separate partition called the "metadata partition" for storing the keymaster blobs that protect this key.

就是一个key,如果没有这个key,userdata数据不能访问。logcat就有类似找不到这个key的错误:

01-01 01:56:53.497   519   519 E vold    : No key found in /metadata/vold/metadata_encryption/key

这个目录fstab指定到keydirectory:

/dev/block/bootdevice/by-name/userdata              /data              f2fs        noatime,nosuid,nodev,discard latemount,wait,check,fileencryption=ice,keydirectory=/metadata/vold/metadata_encryption

ok,我们再来看metadata.img的构成:

#----------------------------------------------------------------------
# Generate metadata image (metadata.img)
# As of now this in empty at build and data is runtime generated only,
# so create an empty fs
#----------------------------------------------------------------------
ifneq ($(strip $(BOARD_METADATAIMAGE_PARTITION_SIZE)),)

TARGET_OUT_METADATA := $(PRODUCT_OUT)/metadata

INSTALLED_METADATAIMAGE_TARGET := $(PRODUCT_OUT)/metadata.img

define build-metadataimage-target
    $(call pretty,"Target metadata fs image: $(INSTALLED_METADATAIMAGE_TARGET)")
    @mkdir -p $(TARGET_OUT_METADATA)
    $(hide)PATH=$(HOST_OUT_EXECUTABLES):$${PATH} $(MKEXTUSERIMG) -s $(TARGET_OUT_METADATA) $@ ext4 metadata $(BOARD_METADATAIMAGE_PARTITION_SIZE)
    $(hide) chmod a+r $@
endef

metadata.img就是一个空目录,so,如果刷了这个img,就是擦了key成新设备,没有这个key,userdata数据就读不出来楼,so要对userdata区恢复下。官方说明如下:

Metadata encryption can only be set up when the data partition is first formatted.

版本起来后看下这个目录,是有货的:

xxx:/metadata/vold/metadata_encryption/key # ls -l
total 52
-rw------- 1 root root   483 1970-01-01 00:49 encrypted_key
-rw------- 1 root root   455 1970-01-01 00:49 keymaster_key_blob
-rw------- 1 root root 16384 1970-01-01 00:49 secdiscardable
-rw------- 1 root root    10 1970-01-01 00:49 stretching
-rw------- 1 root root     1 1970-01-01 00:49 version

我们在recovery模式下也能看到恢复出厂时check metadata是否挂载,如果有就erase。

constexpr const char* METADATA_ROOT = "/metadata";

bool WipeData(Device* device, bool convert_fbe) {
  RecoveryUI* ui = device->GetUI();
  ui->Print("\n-- Wiping data...\n");
  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) { //tj: here
      success &= EraseVolume(METADATA_ROOT, ui, false);
    }
  }
  if (success) {
    success &= device->PostWipeData();
  }
  ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
  return success;
}

另外有个宏用来创建这个挂载点:

# Define BOARD_USES_METADATA_PARTITION to create metadata mount point in system image
BOARD_USES_METADATA_PARTITION := true
ifdef BOARD_USES_METADATA_PARTITION
  LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/metadata
endif

参考文档