Generate block list info file of .img files

This is a text file with block size information of the contents of the
.img files. build_image supports creating this as an implicit output.
This CL creates the build rule to generate this output. This
will be copied to IMAGES/ subdir of target_files.zip

There is a subtle difference between the make and soong implementation.
In make, we generate two $partiton.img files. One is hermetic (for
targret_files.zip), and other is non-hermetic (for adb sync). The block
file is generated from the hermetic one.

OTOH, in the soong implementation, we are generating the block file from
the non-hermetic one. This should not matter, since pinning the
timestamp should not have an effect on block sizes. This implementation
detail can be changed in a follow up CL if necessary.

Test: diff'd target_files.zip locally, all $partition.map files are
identical
Bug: 388635097

Change-Id: I984d4fb55071296a82dae38ef09be6804ff0f3ae
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index c8c5354..8332bc5 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -378,6 +378,7 @@
 		if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
 			for _, partition := range android.SortedKeys(info.SubImageInfo) {
 				builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].Output).Textf(" %s/IMAGES/", targetFilesDir.String())
+				builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].MapFile).Textf(" %s/IMAGES/", targetFilesDir.String())
 			}
 		} else {
 			ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name())
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 85facee..469fd9e 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -369,6 +369,9 @@
 	// to add a dependency on the Output file, as you cannot add dependencies on directories
 	// in ninja.
 	RootDir android.Path
+	// A text file with block data of the .img file
+	// This is an implicit output of `build_image`
+	MapFile android.Path
 }
 
 var FilesystemProvider = blueprint.NewProvider[FilesystemInfo]()
@@ -456,9 +459,11 @@
 	}
 
 	var rootDir android.OutputPath
+	var mapFile android.Path
 	switch f.fsType(ctx) {
 	case ext4Type, erofsType, f2fsType:
 		f.output, rootDir = f.buildImageUsingBuildImage(ctx)
+		mapFile = f.getMapFile(ctx)
 	case compressedCpioType:
 		f.output, rootDir = f.buildCpioImage(ctx, true)
 	case cpioType:
@@ -478,11 +483,16 @@
 	fileListFile := android.PathForModuleOut(ctx, "fileList")
 	android.WriteFileRule(ctx, fileListFile, f.installedFilesList())
 
-	android.SetProvider(ctx, FilesystemProvider, FilesystemInfo{
+	fsInfo := FilesystemInfo{
 		Output:       f.output,
 		FileListFile: fileListFile,
 		RootDir:      rootDir,
-	})
+	}
+	if mapFile != nil {
+		fsInfo.MapFile = mapFile
+	}
+
+	android.SetProvider(ctx, FilesystemProvider, fsInfo)
 
 	f.fileListFile = fileListFile
 
@@ -491,6 +501,11 @@
 	}
 }
 
+func (f *filesystem) getMapFile(ctx android.ModuleContext) android.WritablePath {
+	// create the filepath by replacing the extension of the corresponding img file
+	return android.PathForModuleOut(ctx, f.installFileName()).ReplaceExtension(ctx, "map")
+}
+
 func (f *filesystem) validateVintfFragments(ctx android.ModuleContext) {
 	visitedModule := map[string]bool{}
 	packagingSpecs := f.gatherFilteredPackagingSpecs(ctx)
@@ -671,6 +686,7 @@
 	pathToolDirs := []string{filepath.Dir(fec.String())}
 
 	output := android.PathForModuleOut(ctx, f.installFileName())
+	builder.Command().Text("touch").Output(f.getMapFile(ctx))
 	builder.Command().
 		Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")).
 		BuiltTool("build_image").
@@ -732,6 +748,7 @@
 		}
 		panic(fmt.Errorf("unsupported fs type %v", t))
 	}
+	addStr("block_list", f.getMapFile(ctx).String()) // This will be an implicit output
 
 	addStr("fs_type", fsTypeStr(f.fsType(ctx)))
 	addStr("mount_point", proptools.StringDefault(f.properties.Mount_point, "/"))