Add OverlayManagerImpl to create frro, idmap and get overlayInfos

Add OverlayManagerImpl to let applications create frro and idmap files
for overlaying itself's android resources.
* OverlayManagerImpl.java
  * check the FabricatedOverlayInternal.
* com_android_internal_content_om_OverlayManagerImpl.cpp
  * convert and read Java objects to native data.
  * call the APIs in libidmap2 to create frro and idmap files.

Add OverlayManagerImpl.cpp into AndroidRuntime by modifying Android.bp
* Add register_com_android_internal_content_om_OverlayManagerImpl
  register JNI methods
* add com_android_internal_content_om_OverlayManagerImpl.cpp
    * It's a adapter to delegate the tasks to SelfTargeting.cpp
    * dynamic link with libidmap2 by using dlopen and dlsym to call
      functions in libidmap2.

Add SelfTargeting.cpp into libidmap2
* createFrroFile
* createIdmapFile
* getFabricatedOverlayInfo

for interoperability between libandroid_runtime and libidmap2.
* move OverlayManifestInfo from libidmap2 to libandroidfw
* add FabricatedOverlayEntryParameters into libandroidfw

Bug: 205919743

Test: build
Test: atest \
                  OverlayHostTests \
                  OverlayDeviceTests \
                  SelfTargetingOverlayDeviceTests \
                  OverlayRemountedTest \
                  FrameworksServicesTests:com.android.server.om \
                  CtsContentTestCases:android.content.om.cts \
                  idmap2_tests

Change-Id: I5425f3229e9a3858e57427ef84e6abaf32e89b6e
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 7a08cbd..5f06c97 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -71,6 +71,7 @@
     host_supported: true,
     srcs: [
         "libidmap2/**/*.cpp",
+        "self_targeting/*.cpp",
     ],
     export_include_dirs: ["include"],
     target: {
diff --git a/cmds/idmap2/include/idmap2/ResourceContainer.h b/cmds/idmap2/include/idmap2/ResourceContainer.h
index 2452ff0..4d28321 100644
--- a/cmds/idmap2/include/idmap2/ResourceContainer.h
+++ b/cmds/idmap2/include/idmap2/ResourceContainer.h
@@ -46,14 +46,6 @@
   ~TargetResourceContainer() override = default;
 };
 
-struct OverlayManifestInfo {
-  std::string package_name;     // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string name;             // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string target_package;   // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string target_name;      // NOLINT(misc-non-private-member-variables-in-classes)
-  ResourceId resource_mapping;  // NOLINT(misc-non-private-member-variables-in-classes)
-};
-
 struct OverlayData {
   struct ResourceIdValue {
     // The overlay resource id.
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index 2214a83..c2b0abe 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -30,13 +30,13 @@
 #define EXTRACT_ENTRY(resid) (0x0000ffff & (resid))
 
 // use typedefs to let the compiler warn us about implicit casts
-using ResourceId = uint32_t;  // 0xpptteeee
+using ResourceId = android::ResourceId;  // 0xpptteeee
 using PackageId = uint8_t;    // pp in 0xpptteeee
 using TypeId = uint8_t;       // tt in 0xpptteeee
 using EntryId = uint16_t;     // eeee in 0xpptteeee
 
-using DataType = uint8_t;    // Res_value::dataType
-using DataValue = uint32_t;  // Res_value::data
+using DataType = android::DataType;    // Res_value::dataType
+using DataValue = android::DataValue;  // Res_value::data
 
 struct TargetValue {
   DataType data_type;
diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp
new file mode 100644
index 0000000..20aa7d3
--- /dev/null
+++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/stat.h>
+
+#include <fstream>
+#include <optional>
+
+#define LOG_TAG "SelfTargeting"
+
+#include "androidfw/ResourceTypes.h"
+#include "idmap2/BinaryStreamVisitor.h"
+#include "idmap2/FabricatedOverlay.h"
+#include "idmap2/Idmap.h"
+#include "idmap2/Result.h"
+
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+using android::idmap2::BinaryStreamVisitor;
+using android::idmap2::Idmap;
+using android::idmap2::OverlayResourceContainer;
+
+namespace android::self_targeting {
+
+constexpr const mode_t kIdmapFilePermission = S_IRUSR | S_IWUSR;  // u=rw-, g=---, o=---
+
+extern "C" bool
+CreateFrroFile(std::string& out_err_result, std::string& packageName, std::string& overlayName,
+               std::string& targetPackageName, std::optional<std::string>& targetOverlayable,
+               std::vector<FabricatedOverlayEntryParameters>& entries_params,
+               const std::string& frro_file_path) {
+    android::idmap2::FabricatedOverlay::Builder builder(packageName, overlayName,
+                                                        targetPackageName);
+    if (targetOverlayable.has_value()) {
+        builder.SetOverlayable(targetOverlayable.value_or(std::string()));
+    }
+    for (const auto& entry_params : entries_params) {
+        const auto dataType = entry_params.data_type;
+        if (entry_params.data_binary_value.has_value()) {
+            builder.SetResourceValue(entry_params.resource_name, *entry_params.data_binary_value,
+                                     entry_params.configuration);
+        } else  if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
+           builder.SetResourceValue(entry_params.resource_name, dataType,
+                                    entry_params.data_value, entry_params.configuration);
+        } else if (dataType == Res_value::TYPE_STRING) {
+           builder.SetResourceValue(entry_params.resource_name, dataType,
+                                    entry_params.data_string_value , entry_params.configuration);
+        } else {
+            out_err_result = base::StringPrintf("Unsupported data type %d", dataType);
+            return false;
+        }
+    }
+
+    const auto frro = builder.Build();
+    std::ofstream fout(frro_file_path);
+    if (fout.fail()) {
+        out_err_result = base::StringPrintf("open output stream fail %s", std::strerror(errno));
+        return false;
+    }
+    auto result = frro->ToBinaryStream(fout);
+    if (!result) {
+        unlink(frro_file_path.c_str());
+        out_err_result = base::StringPrintf("to stream fail %s", result.GetErrorMessage().c_str());
+        return false;
+    }
+    fout.close();
+    if (fout.fail()) {
+        unlink(frro_file_path.c_str());
+        out_err_result = base::StringPrintf("output stream fail %s", std::strerror(errno));
+        return false;
+    }
+    if (chmod(frro_file_path.c_str(), kIdmapFilePermission) == -1) {
+        out_err_result = base::StringPrintf("Failed to change the file permission %s",
+                                            frro_file_path.c_str());
+        return false;
+    }
+    return true;
+}
+
+extern "C" bool
+CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::string& overlayPath,
+                const std::string& idmapPath, const std::string& overlayName) {
+    // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap
+    // guarantees that existing memory maps will continue to be valid and unaffected. The file must
+    // be deleted before attempting to create the idmap, so that if idmap  creation fails, the
+    // overlay will no longer be usable.
+    unlink(idmapPath.c_str());
+
+    const auto target = idmap2::TargetResourceContainer::FromPath(targetPath);
+    if (!target) {
+        out_err = base::StringPrintf("Failed to load target %s because of %s", targetPath.c_str(),
+                                     target.GetErrorMessage().c_str());
+        return false;
+    }
+
+    const auto overlay = OverlayResourceContainer::FromPath(overlayPath);
+    if (!overlay) {
+        out_err = base::StringPrintf("Failed to load overlay %s because of %s", overlayPath.c_str(),
+                                     overlay.GetErrorMessage().c_str());
+        return false;
+    }
+
+    // Overlay self target process. Only allow self-targeting types.
+    const auto fulfilled_policies = static_cast<PolicyBitmask>(
+            PolicyFlags::PUBLIC | PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION |
+            PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE | PolicyFlags::ODM_PARTITION |
+            PolicyFlags::OEM_PARTITION | PolicyFlags::ACTOR_SIGNATURE |
+            PolicyFlags::CONFIG_SIGNATURE);
+
+    const auto idmap = Idmap::FromContainers(**target, **overlay, overlayName,
+                                             fulfilled_policies, false /* enforce_overlayable */);
+    if (!idmap) {
+        out_err = base::StringPrintf("Failed to create idmap because of %s",
+                                     idmap.GetErrorMessage().c_str());
+        return false;
+    }
+
+    std::ofstream fout(idmapPath.c_str());
+    if (fout.fail()) {
+        out_err = base::StringPrintf("Failed to create idmap %s because of %s", idmapPath.c_str(),
+                                     strerror(errno));
+        return false;
+    }
+
+    BinaryStreamVisitor visitor(fout);
+    (*idmap)->accept(&visitor);
+    fout.close();
+    if (fout.fail()) {
+        unlink(idmapPath.c_str());
+        out_err = base::StringPrintf("Failed to write idmap %s because of %s", idmapPath.c_str(),
+                                     strerror(errno));
+        return false;
+    }
+    if (chmod(idmapPath.c_str(), kIdmapFilePermission) == -1) {
+        out_err = base::StringPrintf("Failed to change the file permission %s", idmapPath.c_str());
+        return false;
+    }
+    return true;
+}
+
+extern "C" bool
+GetFabricatedOverlayInfo(std::string& out_err, const std::string& overlay_path,
+                         OverlayManifestInfo& out_info) {
+    const auto overlay = idmap2::FabricatedOverlayContainer::FromPath(overlay_path);
+    if (!overlay) {
+        out_err = base::StringPrintf("Failed to write idmap %s because of %s",
+                                     overlay_path.c_str(), strerror(errno));
+        return false;
+    }
+
+    out_info = (*overlay)->GetManifestInfo();
+
+    return true;
+}
+
+}  // namespace android::self_targeting
+
diff --git a/core/java/com/android/internal/content/om/OverlayManagerImpl.java b/core/java/com/android/internal/content/om/OverlayManagerImpl.java
new file mode 100644
index 0000000..76e068d
--- /dev/null
+++ b/core/java/com/android/internal/content/om/OverlayManagerImpl.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.content.om;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+import static com.android.internal.content.om.OverlayConfig.DEFAULT_PRIORITY;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
+import android.os.FabricatedOverlayInfo;
+import android.os.FabricatedOverlayInternal;
+import android.os.FabricatedOverlayInternalEntry;
+import android.os.FileUtils;
+import android.os.Process;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * This class provides the functionalities of registering an overlay, unregistering an overlay, and
+ * getting the list of overlays information.
+ */
+public class OverlayManagerImpl {
+    private static final String TAG = "OverlayManagerImpl";
+    private static final boolean DEBUG = false;
+
+    private static final String FRRO_EXTENSION = ".frro";
+
+    private static final String IDMAP_EXTENSION = ".idmap";
+
+    @VisibleForTesting(visibility = PRIVATE)
+    public static final String SELF_TARGET = ".self_target";
+
+    @NonNull
+    private final Context mContext;
+    private Path mBasePath;
+
+    /**
+     * Init a OverlayManagerImpl by the context.
+     *
+     * @param context the context to create overlay environment
+     */
+    @VisibleForTesting(visibility = PACKAGE)
+    public OverlayManagerImpl(@NonNull Context context) {
+        mContext = Objects.requireNonNull(context);
+
+        if (!Process.myUserHandle().equals(context.getUser())) {
+            throw new SecurityException("Self-Targeting doesn't support multiple user now!");
+        }
+    }
+
+    private static void cleanExpiredOverlays(Path selfTargetingBasePath,
+            Path folderForCurrentBaseApk) {
+        try {
+            final String currentBaseFolder = folderForCurrentBaseApk.toString();
+            final String selfTargetingDir = selfTargetingBasePath.getFileName().toString();
+            Files.walkFileTree(
+                    selfTargetingBasePath,
+                    new SimpleFileVisitor<>() {
+                        @Override
+                        public FileVisitResult preVisitDirectory(Path dir,
+                                                                 BasicFileAttributes attrs)
+                                throws IOException {
+                            final String fileName = dir.getFileName().toString();
+                            return fileName.equals(currentBaseFolder)
+                                    ? FileVisitResult.SKIP_SUBTREE
+                                    : super.preVisitDirectory(dir, attrs);
+                        }
+
+                        @Override
+                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                                throws IOException {
+                            if (!file.toFile().delete()) {
+                                Log.w(TAG, "Failed to delete file " + file);
+                            }
+                            return super.visitFile(file, attrs);
+                        }
+
+                        @Override
+                        public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                                throws IOException {
+                            final String fileName = dir.getFileName().toString();
+                            if (!fileName.equals(currentBaseFolder)
+                                    && !fileName.equals(selfTargetingDir)) {
+                                if (!dir.toFile().delete()) {
+                                    Log.w(TAG, "Failed to delete dir " + dir);
+                                }
+                            }
+                            return super.postVisitDirectory(dir, exc);
+                        }
+                    });
+        } catch (IOException e) {
+            Log.w(TAG, "Unknown fail " + e);
+        }
+    }
+
+    /**
+     * Ensure the base dir for self-targeting is valid.
+     */
+    @VisibleForTesting
+    public void ensureBaseDir() {
+        final String baseApkPath = mContext.getApplicationInfo().getBaseCodePath();
+        final Path baseApkFolderName = Path.of(baseApkPath).getParent().getFileName();
+        final File selfTargetingBaseFile = mContext.getDir(SELF_TARGET, MODE_PRIVATE);
+        Preconditions.checkArgument(
+                selfTargetingBaseFile.isDirectory()
+                        && selfTargetingBaseFile.exists()
+                        && selfTargetingBaseFile.canWrite()
+                        && selfTargetingBaseFile.canRead()
+                        && selfTargetingBaseFile.canExecute(),
+                "Can't work for this context");
+        cleanExpiredOverlays(selfTargetingBaseFile.toPath(), baseApkFolderName);
+
+        final File baseFile = new File(selfTargetingBaseFile, baseApkFolderName.toString());
+        if (!baseFile.exists()) {
+            if (!baseFile.mkdirs()) {
+                Log.w(TAG, "Failed to create directory " + baseFile);
+            }
+
+            // It fails to create frro and idmap files without this setting.
+            FileUtils.setPermissions(
+                    baseFile,
+                    FileUtils.S_IRWXU,
+                    -1 /* uid unchanged */,
+                    -1 /* gid unchanged */);
+        }
+        Preconditions.checkArgument(
+                baseFile.isDirectory()
+                        && baseFile.exists()
+                        && baseFile.canWrite()
+                        && baseFile.canRead()
+                        && baseFile.canExecute(), // 'list' capability
+                "Can't create a workspace for this context");
+
+        mBasePath = baseFile.toPath();
+    }
+
+    /**
+     * Check if the overlay name is valid or not.
+     *
+     * @param name the non-check overlay name
+     * @return the valid overlay name
+     */
+    private static String checkOverlayNameValid(@NonNull String name) {
+        final String overlayName =
+                Preconditions.checkStringNotEmpty(
+                        name, "overlayName should be neither empty nor null string");
+        final String checkOverlayNameResult =
+                FrameworkParsingPackageUtils.validateName(
+                        overlayName, false /* requireSeparator */, true /* requireFilename */);
+        Preconditions.checkArgument(
+                checkOverlayNameResult == null,
+                TextUtils.formatSimple(
+                        "Invalid overlayName \"%s\". The check result is %s.",
+                        overlayName, checkOverlayNameResult));
+        return overlayName;
+    }
+
+    private void checkPackageName(@NonNull String packageName) {
+        Preconditions.checkStringNotEmpty(packageName);
+        Preconditions.checkArgument(
+                TextUtils.equals(mContext.getPackageName(), packageName),
+                TextUtils.formatSimple(
+                        "UID %d doesn't own the package %s", Process.myUid(), packageName));
+    }
+
+    /**
+     * Save FabricatedOverlay instance as frro and idmap files.
+     *
+     * @param overlayInternal the FabricatedOverlayInternal to be saved.
+     */
+    public void registerFabricatedOverlay(@NonNull FabricatedOverlayInternal overlayInternal)
+            throws IOException, PackageManager.NameNotFoundException {
+        ensureBaseDir();
+        Objects.requireNonNull(overlayInternal);
+        final List<FabricatedOverlayInternalEntry> entryList =
+                Objects.requireNonNull(overlayInternal.entries);
+        Preconditions.checkArgument(!entryList.isEmpty(), "overlay entries shouldn't be empty");
+        final String overlayName = checkOverlayNameValid(overlayInternal.overlayName);
+        checkPackageName(overlayInternal.packageName);
+        checkPackageName(overlayInternal.targetPackageName);
+
+        final ApplicationInfo applicationInfo = mContext.getApplicationInfo();
+        final String targetPackage = Preconditions.checkStringNotEmpty(
+                applicationInfo.getBaseCodePath());
+        final Path frroPath = mBasePath.resolve(overlayName + FRRO_EXTENSION);
+        final Path idmapPath = mBasePath.resolve(overlayName + IDMAP_EXTENSION);
+
+        createFrroFile(frroPath.toString(), overlayInternal);
+        try {
+            createIdmapFile(targetPackage, frroPath.toString(), idmapPath.toString(), overlayName);
+        } catch (IOException e) {
+            if (!frroPath.toFile().delete()) {
+                Log.w(TAG, "Failed to delete file " + frroPath);
+            }
+            throw e;
+        }
+    }
+
+    /**
+     * Remove the overlay with the specific name
+     *
+     * @param overlayName the specific name
+     */
+    public void unregisterFabricatedOverlay(@NonNull String overlayName) {
+        ensureBaseDir();
+        checkOverlayNameValid(overlayName);
+        final Path frroPath = mBasePath.resolve(overlayName + FRRO_EXTENSION);
+        final Path idmapPath = mBasePath.resolve(overlayName + IDMAP_EXTENSION);
+
+        if (!frroPath.toFile().delete()) {
+            Log.w(TAG, "Failed to delete file " + frroPath);
+        }
+        if (!idmapPath.toFile().delete()) {
+            Log.w(TAG, "Failed to delete file " + idmapPath);
+        }
+    }
+
+    /**
+     * Get the list of overlays information for the target package name.
+     *
+     * @param targetPackage the target package name
+     * @return the list of overlays information.
+     */
+    @NonNull
+    public List<OverlayInfo> getOverlayInfosForTarget(@NonNull String targetPackage) {
+        ensureBaseDir();
+
+        final File base = mBasePath.toFile();
+        final File[] frroFiles = base.listFiles((dir, name) -> {
+            if (!name.endsWith(FRRO_EXTENSION)) {
+                return false;
+            }
+
+            final String idmapFileName = name.substring(0, name.length() - FRRO_EXTENSION.length())
+                    + IDMAP_EXTENSION;
+            final File idmapFile = new File(dir, idmapFileName);
+            return idmapFile.exists();
+        });
+
+        final ArrayList<OverlayInfo> overlayInfos = new ArrayList<>();
+        for (File file : frroFiles) {
+            final FabricatedOverlayInfo fabricatedOverlayInfo;
+            try {
+                fabricatedOverlayInfo = getFabricatedOverlayInfo(file.getAbsolutePath());
+            } catch (IOException e) {
+                Log.w(TAG, "can't load " + file);
+                continue;
+            }
+            if (!TextUtils.equals(targetPackage, fabricatedOverlayInfo.targetPackageName)) {
+                continue;
+            }
+            if (DEBUG) {
+                Log.i(TAG, "load " + file);
+            }
+
+            final OverlayInfo overlayInfo =
+                    new OverlayInfo(
+                            fabricatedOverlayInfo.packageName,
+                            fabricatedOverlayInfo.overlayName,
+                            fabricatedOverlayInfo.targetPackageName,
+                            fabricatedOverlayInfo.targetOverlayable,
+                            null,
+                            file.getAbsolutePath(),
+                            OverlayInfo.STATE_ENABLED,
+                            UserHandle.myUserId(),
+                            DEFAULT_PRIORITY,
+                            true /* isMutable */,
+                            true /* isFabricated */);
+            overlayInfos.add(overlayInfo);
+        }
+        return overlayInfos;
+    }
+
+    private static native void createFrroFile(
+            @NonNull String frroFile, @NonNull FabricatedOverlayInternal fabricatedOverlayInternal)
+            throws IOException;
+
+    private static native void createIdmapFile(
+            @NonNull String targetPath,
+            @NonNull String overlayPath,
+            @NonNull String idmapPath,
+            @NonNull String overlayName)
+            throws IOException;
+
+    private static native FabricatedOverlayInfo getFabricatedOverlayInfo(
+            @NonNull String overlayPath) throws IOException;
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index d8b91c7..f140e79 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -215,6 +215,7 @@
                 "android_content_res_ResourceTimer.cpp",
                 "android_security_Scrypt.cpp",
                 "com_android_internal_content_om_OverlayConfig.cpp",
+                "com_android_internal_content_om_OverlayManagerImpl.cpp",
                 "com_android_internal_expresslog_Counter.cpp",
                 "com_android_internal_net_NetworkUtilsInternal.cpp",
                 "com_android_internal_os_ClassLoaderFactory.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f549cd8..9e563de 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -198,6 +198,7 @@
 extern int register_com_android_internal_content_F2fsUtils(JNIEnv* env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env);
+extern int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env);
 extern int register_com_android_internal_expresslog_Counter(JNIEnv* env);
 extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env);
 extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
@@ -1587,6 +1588,7 @@
         REG_JNI(register_android_os_SharedMemory),
         REG_JNI(register_android_os_incremental_IncrementalManager),
         REG_JNI(register_com_android_internal_content_om_OverlayConfig),
+        REG_JNI(register_com_android_internal_content_om_OverlayManagerImpl),
         REG_JNI(register_com_android_internal_expresslog_Counter),
         REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
         REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
diff --git a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
new file mode 100644
index 0000000..df55e42
--- /dev/null
+++ b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlfcn.h>
+
+#include <optional>
+
+#define LOG_TAG "OverlayManagerImpl"
+
+#include "android-base/no_destructor.h"
+#include "androidfw/ResourceTypes.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+namespace android {
+
+static struct fabricated_overlay_internal_offsets_t {
+    jclass classObject;
+    jfieldID packageName;
+    jfieldID overlayName;
+    jfieldID targetPackageName;
+    jfieldID targetOverlayable;
+    jfieldID entries;
+} gFabricatedOverlayInternalOffsets;
+
+static struct fabricated_overlay_internal_entry_offsets_t {
+    jclass classObject;
+    jfieldID resourceName;
+    jfieldID dataType;
+    jfieldID data;
+    jfieldID stringData;
+    jfieldID binaryData;
+    jfieldID configuration;
+} gFabricatedOverlayInternalEntryOffsets;
+
+static struct parcel_file_descriptor_offsets_t {
+    jclass classObject;
+    jmethodID getFd;
+} gParcelFileDescriptorOffsets;
+
+static struct List_offsets_t {
+    jclass classObject;
+    jmethodID size;
+    jmethodID get;
+} gListOffsets;
+
+static struct fabricated_overlay_info_offsets_t {
+    jclass classObject;
+    jmethodID constructor;
+    jfieldID packageName;
+    jfieldID overlayName;
+    jfieldID targetPackageName;
+    jfieldID targetOverlayable;
+    jfieldID path;
+} gFabricatedOverlayInfoOffsets;
+
+namespace self_targeting {
+
+constexpr const char kIOException[] = "java/io/IOException";
+constexpr const char IllegalArgumentException[] = "java/lang/IllegalArgumentException";
+
+class DynamicLibraryLoader {
+public:
+    explicit DynamicLibraryLoader(JNIEnv* env) {
+        /* For SelfTargeting, there are 2 types of files to be handled. One is frro and the other is
+         * idmap. For creating frro/idmap files and reading frro files, it needs libandroid_runtime
+         * to do a shared link to libidmap2. However, libidmap2 contains the codes generated from
+         * google protocol buffer. When libandroid_runtime does a shared link to libidmap2, it will
+         * impact the memory for system_server and zygote(a.k.a. all applications).
+         *
+         * Not all applications need to either create/read frro files or create idmap files all the
+         * time. When the apps apply the SelfTargeting overlay effect, it only needs libandroifw
+         * that is loaded. To use dlopen(libidmap2.so) is to make sure that applications don't
+         * impact themselves' memory by loading libidmap2 until they need to create/read frro files
+         * or create idmap files.
+         */
+        handle_ = dlopen("libidmap2.so", RTLD_NOW);
+        if (handle_ == nullptr) {
+            jniThrowNullPointerException(env);
+            return;
+        }
+
+        createIdmapFileFuncPtr_ =
+                reinterpret_cast<CreateIdmapFileFunc>(dlsym(handle_, "CreateIdmapFile"));
+        if (createIdmapFileFuncPtr_ == nullptr) {
+            jniThrowNullPointerException(env, "The symbol CreateIdmapFile is not found.");
+            return;
+        }
+        getFabricatedOverlayInfoFuncPtr_ = reinterpret_cast<GetFabricatedOverlayInfoFunc>(
+                dlsym(handle_, "GetFabricatedOverlayInfo"));
+        if (getFabricatedOverlayInfoFuncPtr_ == nullptr) {
+            jniThrowNullPointerException(env, "The symbol GetFabricatedOverlayInfo is not found.");
+            return;
+        }
+        createFrroFile_ = reinterpret_cast<CreateFrroFileFunc>(dlsym(handle_, "CreateFrroFile"));
+        if (createFrroFile_ == nullptr) {
+            jniThrowNullPointerException(env, "The symbol CreateFrroFile is not found.");
+            return;
+        }
+    }
+
+    bool callCreateFrroFile(std::string& out_error, const std::string& packageName,
+                            const std::string& overlayName, const std::string& targetPackageName,
+                            const std::optional<std::string>& targetOverlayable,
+                            const std::vector<FabricatedOverlayEntryParameters>& entries_params,
+                            const std::string& frro_file_path) {
+        return createFrroFile_(out_error, packageName, overlayName, targetPackageName,
+                               targetOverlayable, entries_params, frro_file_path);
+    }
+
+    bool callCreateIdmapFile(std::string& out_error, const std::string& targetPath,
+                             const std::string& overlayPath, const std::string& idmapPath,
+                             const std::string& overlayName) {
+        return createIdmapFileFuncPtr_(out_error, targetPath, overlayPath, idmapPath, overlayName);
+    }
+
+    bool callGetFabricatedOverlayInfo(std::string& out_error, const std::string& overlay_path,
+                                      OverlayManifestInfo& out_overlay_manifest_info) {
+        return getFabricatedOverlayInfoFuncPtr_(out_error, overlay_path, out_overlay_manifest_info);
+    }
+
+    explicit operator bool() const {
+        return handle_ != nullptr && createFrroFile_ != nullptr &&
+                createIdmapFileFuncPtr_ != nullptr && getFabricatedOverlayInfoFuncPtr_ != nullptr;
+    }
+
+    DynamicLibraryLoader(const DynamicLibraryLoader&) = delete;
+
+    DynamicLibraryLoader& operator=(const DynamicLibraryLoader&) = delete;
+
+    ~DynamicLibraryLoader() {
+        if (handle_ != nullptr) {
+            dlclose(handle_);
+        }
+    }
+
+private:
+    typedef bool (*CreateFrroFileFunc)(
+            std::string& out_error, const std::string& packageName, const std::string& overlayName,
+            const std::string& targetPackageName,
+            const std::optional<std::string>& targetOverlayable,
+            const std::vector<FabricatedOverlayEntryParameters>& entries_params,
+            const std::string& frro_file_path);
+
+    typedef bool (*CreateIdmapFileFunc)(std::string& out_error, const std::string& targetPath,
+                                        const std::string& overlayPath,
+                                        const std::string& idmapPath,
+                                        const std::string& overlayName);
+
+    typedef bool (*GetFabricatedOverlayInfoFunc)(std::string& out_error,
+                                                 const std::string& overlay_path,
+                                                 OverlayManifestInfo& out_overlay_manifest_info);
+
+    void* handle_;
+    CreateFrroFileFunc createFrroFile_;
+    CreateIdmapFileFunc createIdmapFileFuncPtr_;
+    GetFabricatedOverlayInfoFunc getFabricatedOverlayInfoFuncPtr_;
+};
+
+static DynamicLibraryLoader& EnsureDynamicLibraryLoader(JNIEnv* env) {
+    static android::base::NoDestructor<DynamicLibraryLoader> loader(env);
+    return *loader;
+}
+
+static std::optional<std::string> getNullableString(JNIEnv* env, jobject object, jfieldID field) {
+    auto javaString = reinterpret_cast<jstring>(env->GetObjectField(object, field));
+    if (javaString == nullptr) {
+        return std::nullopt;
+    }
+
+    const ScopedUtfChars result(env, javaString);
+    if (result.c_str() == nullptr) {
+        return std::nullopt;
+    }
+
+    return std::optional<std::string>{result.c_str()};
+}
+
+static std::optional<android::base::borrowed_fd> getNullableFileDescriptor(JNIEnv* env,
+                                                                           jobject object,
+                                                                           jfieldID field) {
+    auto binaryData = env->GetObjectField(object, field);
+    if (binaryData == nullptr) {
+        return std::nullopt;
+    }
+
+    return env->CallIntMethod(binaryData, gParcelFileDescriptorOffsets.getFd);
+}
+
+static void CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath, jobject overlay) {
+    DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
+    if (!dlLoader) {
+        jniThrowNullPointerException(env, "libidmap2 is not loaded");
+        return;
+    }
+
+    if (overlay == nullptr) {
+        jniThrowNullPointerException(env, "overlay is null");
+        return;
+    }
+    auto jsPackageName =
+            (jstring)env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.packageName);
+    const ScopedUtfChars packageName(env, jsPackageName);
+    if (packageName.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "packageName is null");
+        return;
+    }
+    auto jsOverlayName =
+            (jstring)env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.overlayName);
+    const ScopedUtfChars overlayName(env, jsOverlayName);
+    if (overlayName.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "overlayName is null");
+        return;
+    }
+    auto jsTargetPackageName =
+            (jstring)env->GetObjectField(overlay,
+                                         gFabricatedOverlayInternalOffsets.targetPackageName);
+    const ScopedUtfChars targetPackageName(env, jsTargetPackageName);
+    if (targetPackageName.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "targetPackageName is null");
+        return;
+    }
+    auto overlayable =
+            getNullableString(env, overlay, gFabricatedOverlayInternalOffsets.targetOverlayable);
+    const ScopedUtfChars frroFilePath(env, jsFrroFilePath);
+    if (frroFilePath.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "frroFilePath is null");
+        return;
+    }
+    jobject entries = env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.entries);
+    if (entries == nullptr) {
+        jniThrowNullPointerException(env, "overlay entries is null");
+        return;
+    }
+    const jint size = env->CallIntMethod(entries, gListOffsets.size);
+    ALOGV("frroFilePath = %s, packageName = %s, overlayName = %s, targetPackageName = %s,"
+          " targetOverlayable = %s, size = %d",
+          frroFilePath.c_str(), packageName.c_str(), overlayName.c_str(), targetPackageName.c_str(),
+          overlayable.value_or(std::string()).c_str(), size);
+
+    std::vector<FabricatedOverlayEntryParameters> entries_params;
+    for (jint i = 0; i < size; i++) {
+        jobject entry = env->CallObjectMethod(entries, gListOffsets.get, i);
+        auto jsResourceName = reinterpret_cast<jstring>(
+                env->GetObjectField(entry, gFabricatedOverlayInternalEntryOffsets.resourceName));
+        const ScopedUtfChars resourceName(env, jsResourceName);
+        const auto dataType =
+                env->GetIntField(entry, gFabricatedOverlayInternalEntryOffsets.dataType);
+
+        // In Java, the data type is int but the maximum value of data Type is less than 0xff.
+        if (dataType >= UCHAR_MAX) {
+            jniThrowException(env, IllegalArgumentException, "Unsupported data type");
+            return;
+        }
+
+        const auto data = env->GetIntField(entry, gFabricatedOverlayInternalEntryOffsets.data);
+        auto configuration =
+                getNullableString(env, entry, gFabricatedOverlayInternalEntryOffsets.configuration);
+        auto string_data =
+                getNullableString(env, entry, gFabricatedOverlayInternalEntryOffsets.stringData);
+        auto binary_data =
+                getNullableFileDescriptor(env, entry,
+                                          gFabricatedOverlayInternalEntryOffsets.binaryData);
+        entries_params.push_back(
+                FabricatedOverlayEntryParameters{resourceName.c_str(), (DataType)dataType,
+                                                 (DataValue)data,
+                                                 string_data.value_or(std::string()), binary_data,
+                                                 configuration.value_or(std::string())});
+        ALOGV("resourceName = %s, dataType = 0x%08x, data = 0x%08x, dataString = %s,"
+              " binaryData = %d, configuration = %s",
+              resourceName.c_str(), dataType, data, string_data.value_or(std::string()).c_str(),
+              binary_data.has_value(), configuration.value_or(std::string()).c_str());
+    }
+
+    std::string err_result;
+    if (!dlLoader.callCreateFrroFile(err_result, packageName.c_str(), overlayName.c_str(),
+                                     targetPackageName.c_str(), overlayable, entries_params,
+                                     frroFilePath.c_str())) {
+        jniThrowException(env, IllegalArgumentException, err_result.c_str());
+        return;
+    }
+}
+
+static void CreateIdmapFile(JNIEnv* env, jclass /* clazz */, jstring jsTargetPath,
+                            jstring jsOverlayPath, jstring jsIdmapPath, jstring jsOverlayName) {
+    DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
+    if (!dlLoader) {
+        jniThrowNullPointerException(env, "libidmap2 is not loaded");
+        return;
+    }
+
+    const ScopedUtfChars targetPath(env, jsTargetPath);
+    if (targetPath.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "targetPath is null");
+        return;
+    }
+    const ScopedUtfChars overlayPath(env, jsOverlayPath);
+    if (overlayPath.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "overlayPath is null");
+        return;
+    }
+    const ScopedUtfChars idmapPath(env, jsIdmapPath);
+    if (idmapPath.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "idmapPath is null");
+        return;
+    }
+    const ScopedUtfChars overlayName(env, jsOverlayName);
+    if (overlayName.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "overlayName is null");
+        return;
+    }
+    ALOGV("target_path = %s, overlay_path = %s, idmap_path = %s, overlay_name = %s",
+          targetPath.c_str(), overlayPath.c_str(), idmapPath.c_str(), overlayName.c_str());
+
+    std::string err_result;
+    if (!dlLoader.callCreateIdmapFile(err_result, targetPath.c_str(), overlayPath.c_str(),
+                                      idmapPath.c_str(), overlayName.c_str())) {
+        jniThrowException(env, kIOException, err_result.c_str());
+        return;
+    }
+}
+
+static jobject GetFabricatedOverlayInfo(JNIEnv* env, jclass /* clazz */, jstring jsOverlayPath) {
+    const ScopedUtfChars overlay_path(env, jsOverlayPath);
+    if (overlay_path.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "overlay_path is null");
+        return nullptr;
+    }
+    ALOGV("overlay_path = %s", overlay_path.c_str());
+
+    DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
+    if (!dlLoader) {
+        return nullptr;
+    }
+
+    std::string err_result;
+    OverlayManifestInfo overlay_manifest_info;
+    if (!dlLoader.callGetFabricatedOverlayInfo(err_result, overlay_path.c_str(),
+                                               overlay_manifest_info) != 0) {
+        jniThrowException(env, kIOException, err_result.c_str());
+        return nullptr;
+    }
+    jobject info = env->NewObject(gFabricatedOverlayInfoOffsets.classObject,
+                                  gFabricatedOverlayInfoOffsets.constructor);
+    jstring jsOverName = env->NewStringUTF(overlay_manifest_info.name.c_str());
+    jstring jsPackageName = env->NewStringUTF(overlay_manifest_info.package_name.c_str());
+    jstring jsTargetPackage = env->NewStringUTF(overlay_manifest_info.target_package.c_str());
+    jstring jsTargetOverlayable = env->NewStringUTF(overlay_manifest_info.target_name.c_str());
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.overlayName, jsOverName);
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.packageName, jsPackageName);
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.targetPackageName, jsTargetPackage);
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.targetOverlayable, jsTargetOverlayable);
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.path, jsOverlayPath);
+    return info;
+}
+
+} // namespace self_targeting
+
+// JNI registration.
+static const JNINativeMethod gOverlayManagerMethods[] = {
+        {"createFrroFile", "(Ljava/lang/String;Landroid/os/FabricatedOverlayInternal;)V",
+         reinterpret_cast<void*>(self_targeting::CreateFrroFile)},
+        {"createIdmapFile",
+         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+         reinterpret_cast<void*>(self_targeting::CreateIdmapFile)},
+        {"getFabricatedOverlayInfo", "(Ljava/lang/String;)Landroid/os/FabricatedOverlayInfo;",
+         reinterpret_cast<void*>(self_targeting::GetFabricatedOverlayInfo)},
+};
+
+int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env) {
+    jclass ListClass = FindClassOrDie(env, "java/util/List");
+    gListOffsets.classObject = MakeGlobalRefOrDie(env, ListClass);
+    gListOffsets.size = GetMethodIDOrDie(env, gListOffsets.classObject, "size", "()I");
+    gListOffsets.get =
+            GetMethodIDOrDie(env, gListOffsets.classObject, "get", "(I)Ljava/lang/Object;");
+
+    jclass fabricatedOverlayInternalClass =
+            FindClassOrDie(env, "android/os/FabricatedOverlayInternal");
+    gFabricatedOverlayInternalOffsets.classObject =
+            MakeGlobalRefOrDie(env, fabricatedOverlayInternalClass);
+    gFabricatedOverlayInternalOffsets.packageName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "packageName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalOffsets.overlayName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "overlayName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalOffsets.targetPackageName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "targetPackageName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalOffsets.targetOverlayable =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "targetOverlayable",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalOffsets.entries =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "entries",
+                            "Ljava/util/List;");
+
+    jclass fabricatedOverlayInternalEntryClass =
+            FindClassOrDie(env, "android/os/FabricatedOverlayInternalEntry");
+    gFabricatedOverlayInternalEntryOffsets.classObject =
+            MakeGlobalRefOrDie(env, fabricatedOverlayInternalEntryClass);
+    gFabricatedOverlayInternalEntryOffsets.resourceName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "resourceName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalEntryOffsets.dataType =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "dataType",
+                            "I");
+    gFabricatedOverlayInternalEntryOffsets.data =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "data", "I");
+    gFabricatedOverlayInternalEntryOffsets.stringData =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "stringData",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalEntryOffsets.binaryData =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "binaryData",
+                            "Landroid/os/ParcelFileDescriptor;");
+    gFabricatedOverlayInternalEntryOffsets.configuration =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject,
+                            "configuration", "Ljava/lang/String;");
+
+    jclass parcelFileDescriptorClass =
+            android::FindClassOrDie(env, "android/os/ParcelFileDescriptor");
+    gParcelFileDescriptorOffsets.classObject = MakeGlobalRefOrDie(env, parcelFileDescriptorClass);
+    gParcelFileDescriptorOffsets.getFd =
+            GetMethodIDOrDie(env, gParcelFileDescriptorOffsets.classObject, "getFd", "()I");
+
+    jclass fabricatedOverlayInfoClass = FindClassOrDie(env, "android/os/FabricatedOverlayInfo");
+    gFabricatedOverlayInfoOffsets.classObject = MakeGlobalRefOrDie(env, fabricatedOverlayInfoClass);
+    gFabricatedOverlayInfoOffsets.constructor =
+            GetMethodIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "<init>", "()V");
+    gFabricatedOverlayInfoOffsets.packageName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "packageName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInfoOffsets.overlayName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "overlayName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInfoOffsets.targetPackageName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "targetPackageName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInfoOffsets.targetOverlayable =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "targetOverlayable",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInfoOffsets.path =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "path",
+                            "Ljava/lang/String;");
+
+    return RegisterMethodsOrDie(env, "com/android/internal/content/om/OverlayManagerImpl",
+                                gOverlayManagerMethods, NELEM(gOverlayManagerMethods));
+}
+
+} // namespace android
diff --git a/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp
new file mode 100644
index 0000000..82998db
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "SelfTargetingOverlayDeviceTests",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.runner",
+        "androidx.test.ext.junit",
+        "truth-prebuilt",
+    ],
+
+    optimize: {
+        enabled: false,
+    },
+    test_suites: ["device-tests"],
+}
diff --git a/core/tests/overlaytests/device_self_targeting/AndroidManifest.xml b/core/tests/overlaytests/device_self_targeting/AndroidManifest.xml
new file mode 100644
index 0000000..c121bf2
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.overlaytest.self_targeting">
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.overlaytest.self_targeting"
+        android:label="Self-Targeting resource overlay tests" />
+</manifest>
diff --git a/core/tests/overlaytests/device_self_targeting/res/drawable/mydrawable.webp b/core/tests/overlaytests/device_self_targeting/res/drawable/mydrawable.webp
new file mode 100644
index 0000000..aa7d642
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/res/drawable/mydrawable.webp
Binary files differ
diff --git a/core/tests/overlaytests/device_self_targeting/res/raw/overlay_drawable.webp b/core/tests/overlaytests/device_self_targeting/res/raw/overlay_drawable.webp
new file mode 100644
index 0000000..9126ae3
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/res/raw/overlay_drawable.webp
Binary files differ
diff --git a/core/tests/overlaytests/device_self_targeting/res/values/values.xml b/core/tests/overlaytests/device_self_targeting/res/values/values.xml
new file mode 100644
index 0000000..f0b4a6f
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/res/values/values.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <color name="mycolor">#ff112233</color>
+    <string name="mystring">hello</string>
+</resources>
diff --git a/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
new file mode 100644
index 0000000..ca58410
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.overlaytest;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.internal.content.om.OverlayManagerImpl.SELF_TARGET;
+
+import static org.junit.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.om.OverlayInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.os.FabricatedOverlayInternal;
+import android.os.FabricatedOverlayInternalEntry;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
+import android.util.TypedValue;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.content.om.OverlayManagerImpl;
+import com.android.overlaytest.self_targeting.R;
+
+import com.google.common.truth.Expect;
+import com.google.common.truth.Truth;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This test class verify the interfaces of {@link
+ * com.android.internal.content.om.OverlayManagerImpl}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class OverlayManagerImplTest {
+    private static final String TAG = "OverlayManagerImplTest";
+
+    private static final String TARGET_COLOR_RES = "color/mycolor";
+    private static final String TARGET_STRING_RES = "string/mystring";
+    private static final String TARGET_DRAWABLE_RES = "drawable/mydrawable";
+
+    private Context mContext;
+    private OverlayManagerImpl mOverlayManagerImpl;
+    private String mOverlayName;
+
+    @Rule public TestName mTestName = new TestName();
+
+    @Rule public Expect expect = Expect.create();
+
+    private void clearDir() throws IOException {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final Path basePath = context.getDir(SELF_TARGET, MODE_PRIVATE).toPath();
+        Files.walkFileTree(
+                basePath,
+                new SimpleFileVisitor<>() {
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                            throws IOException {
+                        if (!file.toFile().delete()) {
+                            Log.w(TAG, "Failed to delete file " + file);
+                        }
+                        return super.visitFile(file, attrs);
+                    }
+
+                    @Override
+                    public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                            throws IOException {
+                        if (!dir.toFile().delete()) {
+                            Log.w(TAG, "Failed to delete dir " + dir);
+                        }
+                        return super.postVisitDirectory(dir, exc);
+                    }
+                });
+    }
+
+    @Before
+    public void setUp() throws IOException {
+        clearDir();
+        mOverlayName = mTestName.getMethodName();
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mOverlayManagerImpl = new OverlayManagerImpl(mContext);
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        clearDir();
+    }
+
+    private <T> void addOverlayEntry(
+            FabricatedOverlayInternal overlayInternal,
+            @NonNull List<Pair<String, Pair<String, T>>> entryDefinitions) {
+        List<FabricatedOverlayInternalEntry> entries = new ArrayList<>();
+        for (Pair<String, Pair<String, T>> entryDefinition : entryDefinitions) {
+            FabricatedOverlayInternalEntry internalEntry = new FabricatedOverlayInternalEntry();
+            internalEntry.resourceName = entryDefinition.first;
+            internalEntry.configuration = entryDefinition.second.first;
+            if (entryDefinition.second.second instanceof ParcelFileDescriptor) {
+                internalEntry.binaryData = (ParcelFileDescriptor) entryDefinition.second.second;
+            } else if (entryDefinition.second.second instanceof String) {
+                internalEntry.stringData = (String) entryDefinition.second.second;
+                internalEntry.dataType = TypedValue.TYPE_STRING;
+            } else {
+                internalEntry.data = (int) entryDefinition.second.second;
+                internalEntry.dataType = TypedValue.TYPE_INT_COLOR_ARGB8;
+            }
+            entries.add(internalEntry);
+            overlayInternal.entries = entries;
+        }
+    }
+
+    private <T> FabricatedOverlayInternal createOverlayWithName(
+            @NonNull String overlayName,
+            @NonNull String targetPackageName,
+            @NonNull List<Pair<String, Pair<String, T>>> entryDefinitions) {
+        final String packageName = mContext.getPackageName();
+        FabricatedOverlayInternal overlayInternal = new FabricatedOverlayInternal();
+        overlayInternal.overlayName = overlayName;
+        overlayInternal.targetPackageName = targetPackageName;
+        overlayInternal.packageName = packageName;
+
+        addOverlayEntry(overlayInternal, entryDefinitions);
+
+        return overlayInternal;
+    }
+
+    @Test
+    public void registerOverlay_forAndroidPackage_shouldFail() {
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        "android",
+                        List.of(Pair.create("color/white", Pair.create(null, Color.BLACK))));
+
+        assertThrows(
+                "Wrong target package name",
+                IllegalArgumentException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void getOverlayInfosForTarget_defaultShouldBeZero() {
+        List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+
+        Truth.assertThat(overlayInfos.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void unregisterNonExistingOverlay_shouldBeOk() {
+        mOverlayManagerImpl.unregisterFabricatedOverlay("NotExisting");
+    }
+
+    @Test
+    public void registerOverlay_createColorOverlay_shouldBeSavedInAndLoadFromFile()
+            throws IOException, PackageManager.NameNotFoundException {
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        final OverlayInfo overlayInfo = overlayInfos.get(0);
+        expect.that(overlayInfo).isNotNull();
+        Truth.assertThat(expect.hasFailures()).isFalse();
+        expect.that(overlayInfo.isFabricated()).isTrue();
+        expect.that(overlayInfo.getOverlayName()).isEqualTo(mOverlayName);
+        expect.that(overlayInfo.getPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getTargetPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getUserId()).isEqualTo(mContext.getUserId());
+    }
+
+    @Test
+    public void registerOverlay_createStringOverlay_shouldBeSavedInAndLoadFromFile()
+            throws IOException, PackageManager.NameNotFoundException {
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_STRING_RES, Pair.create(null, "HELLO"))));
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        final OverlayInfo overlayInfo = overlayInfos.get(0);
+        expect.that(overlayInfo).isNotNull();
+        Truth.assertThat(expect.hasFailures()).isFalse();
+        expect.that(overlayInfo.isFabricated()).isTrue();
+        expect.that(overlayInfo.getOverlayName()).isEqualTo(mOverlayName);
+        expect.that(overlayInfo.getPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getTargetPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getUserId()).isEqualTo(mContext.getUserId());
+    }
+
+    @Test
+    public void registerOverlay_createFileOverlay_shouldBeSavedInAndLoadFromFile()
+            throws IOException, PackageManager.NameNotFoundException {
+        ParcelFileDescriptor parcelFileDescriptor = mContext.getResources()
+                .openRawResourceFd(R.raw.overlay_drawable).getParcelFileDescriptor();
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_DRAWABLE_RES,
+                                            Pair.create(null, parcelFileDescriptor))));
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        final OverlayInfo overlayInfo = overlayInfos.get(0);
+        expect.that(overlayInfo).isNotNull();
+        Truth.assertThat(expect.hasFailures()).isFalse();
+        expect.that(overlayInfo.isFabricated()).isTrue();
+        expect.that(overlayInfo.getOverlayName()).isEqualTo(mOverlayName);
+        expect.that(overlayInfo.getPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getTargetPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getUserId()).isEqualTo(mContext.getUserId());
+    }
+
+    @Test
+    public void registerOverlay_notExistedResource_shouldFailWithoutSavingAnyFile()
+            throws IOException {
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        mContext.getPackageName(),
+                        List.of(Pair.create("color/not_existed", Pair.create(null, "HELLO"))));
+
+        assertThrows(IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(0);
+        final int[] fileCounts = new int[1];
+        Files.walkFileTree(
+                mContext.getDir(SELF_TARGET, MODE_PRIVATE).toPath(),
+                new SimpleFileVisitor<>() {
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                            throws IOException {
+                        fileCounts[0]++;
+                        return super.visitFile(file, attrs);
+                    }
+                });
+        expect.that(fileCounts[0]).isEqualTo(0);
+    }
+
+    @Test
+    public void registerMultipleOverlays_shouldMatchTheNumberOfOverlays()
+            throws IOException, PackageManager.NameNotFoundException {
+        final String secondOverlayName = mOverlayName + "2nd";
+        final int initNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final int firstNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+        overlayInternal =
+                createOverlayWithName(
+                        secondOverlayName,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final int secondNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+        mOverlayManagerImpl.unregisterFabricatedOverlay(mOverlayName);
+        mOverlayManagerImpl.unregisterFabricatedOverlay(secondOverlayName);
+        final int finalNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+
+        expect.that(initNumberOfOverlays).isEqualTo(0);
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        expect.that(secondNumberOfOverlays).isEqualTo(2);
+        expect.that(finalNumberOfOverlays).isEqualTo(0);
+    }
+
+    @Test
+    public void unregisterOverlay_withIllegalOverlayName_shouldFail() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mOverlayManagerImpl.unregisterFabricatedOverlay("../../etc/password"));
+    }
+
+    @Test
+    public void registerTheSameOverlay_shouldNotIncreaseTheNumberOfOverlays()
+            throws IOException, PackageManager.NameNotFoundException {
+        final int initNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final int firstNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+        overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final int secondNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+        mOverlayManagerImpl.unregisterFabricatedOverlay(mOverlayName);
+        final int finalNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+
+        expect.that(initNumberOfOverlays).isEqualTo(0);
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        expect.that(secondNumberOfOverlays).isEqualTo(1);
+        expect.that(finalNumberOfOverlays).isEqualTo(0);
+    }
+
+    @Test
+    public void registerOverlay_packageNotOwnedBySelf_shouldFail() {
+        FabricatedOverlayInternal overlayInternal = new FabricatedOverlayInternal();
+        overlayInternal.packageName = "com.android.systemui";
+        overlayInternal.overlayName = mOverlayName;
+        overlayInternal.targetOverlayable = "non-existed-target-overlayable";
+        overlayInternal.targetPackageName = mContext.getPackageName();
+        addOverlayEntry(
+                overlayInternal,
+                List.of(Pair.create("color/white", Pair.create(null, Color.BLACK))));
+
+        assertThrows(
+                "The context doesn't own the package",
+                IllegalArgumentException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void ensureBaseDir_forOtherPackage_shouldFail()
+            throws PackageManager.NameNotFoundException {
+        final Context fakeContext =
+                mContext.createPackageContext("com.android.systemui", 0 /* flags */);
+        final OverlayManagerImpl overlayManagerImpl = new OverlayManagerImpl(fakeContext);
+
+        assertThrows(IllegalArgumentException.class, overlayManagerImpl::ensureBaseDir);
+    }
+
+    @Test
+    public void newOverlayManagerImpl_forOtherUser_shouldFail() {
+        Context fakeContext =
+                new ContextWrapper(mContext) {
+                    @Override
+                    public UserHandle getUser() {
+                        return UserHandle.of(100);
+                    }
+
+                    @Override
+                    public int getUserId() {
+                        return 100;
+                    }
+                };
+
+        assertThrows(SecurityException.class, () -> new OverlayManagerImpl(fakeContext));
+    }
+}
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index c740832..b2b95b7 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1830,6 +1830,28 @@
   return first;
 }
 
+using ResourceId = uint32_t;  // 0xpptteeee
+
+using DataType = uint8_t;    // Res_value::dataType
+using DataValue = uint32_t;  // Res_value::data
+
+struct OverlayManifestInfo {
+  std::string package_name;     // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string name;             // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string target_package;   // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string target_name;      // NOLINT(misc-non-private-member-variables-in-classes)
+  ResourceId resource_mapping;  // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+struct FabricatedOverlayEntryParameters {
+  std::string resource_name;
+  DataType data_type;
+  DataValue data_value;
+  std::string data_string_value;
+  std::optional<android::base::borrowed_fd> data_binary_value;
+  std::string configuration;
+};
+
 class AssetManager2;
 
 /**