Merge "Convert absolute source path to relative path in PRODUCT_COPY_FILES processing" into main
diff --git a/android/paths.go b/android/paths.go
index 3f67c55..8f066cc 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -2613,3 +2613,19 @@
 	}
 	return false
 }
+
+// ToRelativeSourcePath converts absolute source path to the path relative to the source root.
+// This throws an error if the input path is outside of the source root and cannot be converted
+// to the relative path.
+// This should be rarely used given that the source path is relative in Soong.
+func ToRelativeSourcePath(ctx PathContext, path string) string {
+	ret := path
+	if filepath.IsAbs(path) {
+		relPath, err := filepath.Rel(absSrcDir, path)
+		if err != nil || strings.HasPrefix(relPath, "..") {
+			ReportPathErrorf(ctx, "%s is outside of the source root", path)
+		}
+		ret = relPath
+	}
+	return ret
+}
diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
index 983dcfb..73fb8d7 100644
--- a/fsgen/prebuilt_etc_modules_gen.go
+++ b/fsgen/prebuilt_etc_modules_gen.go
@@ -100,10 +100,15 @@
 			ctx.ModuleErrorf("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: %s", copyFilePair)
 		}
 		src, dest := srcDestList[0], srcDestList[1]
+
+		// Some downstream branches use absolute path as entries in PRODUCT_COPY_FILES.
+		// Convert them to relative path from top and check if they do not escape the tree root.
+		relSrc := android.ToRelativeSourcePath(ctx, src)
+
 		if _, ok := seen[dest]; !ok {
-			if optionalPath := android.ExistentPathForSource(ctx, src); optionalPath.Valid() {
+			if optionalPath := android.ExistentPathForSource(ctx, relSrc); optionalPath.Valid() {
 				seen[dest] = true
-				filtered[src] = append(filtered[src], dest)
+				filtered[relSrc] = append(filtered[relSrc], dest)
 			}
 		}
 	}