Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a5b71b1 authored by Jeremy Meyer's avatar Jeremy Meyer
Browse files

Have runtime load RES_TABLE_FLAG_LIST chunks

Test: Modified cts flaggedresources_rw test and tmp logging verified
Bug: 420720496
Flag: android.content.res.resource_readwrite_flags
Change-Id: If52dfc56aa7ba5ea884fba980150b80d516f1d6c
parent cda0f42f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -188,6 +188,7 @@ Result<Unit> Lookup(const std::vector<std::string>& args) {

    if (i == 0) {
      target_path = idmap_header->GetTargetPath();
      // TODO: b/437989879 - Add support for r/w flags in idmap
      auto target_apk = ApkAssets::Load(target_path);
      if (!target_apk) {
        return Error("failed to read target apk from %s", target_path.c_str());
+3 −1
Original line number Diff line number Diff line
@@ -274,7 +274,9 @@ struct ResState {
                                     package_property_t flags) {
    ResState state;
    state.zip_assets = zip.get();
    if ((state.apk_assets = ApkAssets::Load(std::move(zip), flags)) == nullptr) {

    // TODO: b/437989879 - Add support for r/w flags in idmap
    if ((state.apk_assets = ApkAssets::Load(std::move(zip), nullptr, flags)) == nullptr) {
      return Error("failed to load apk asset for '%s'",
                   state.zip_assets->GetDebugName().c_str());
    }
+21 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.text.TextUtils;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;

import dalvik.annotation.optimization.CriticalNative;

@@ -513,6 +514,26 @@ public final class ApkAssets {
        pw.println(prefix + "assetPath=" + getAssetPath());
    }

    /**
     * This exists as a function the native layer can call through jni to determine which android
     * feature flags are enabled.
     *
     * @param flagNames An array of all the names the native layer needs to know the status of
     * @return An array that parallels the flagNames parameter and contains if each flag is enabled
     */
    private static boolean[] getFlagValuesForNative(@NonNull String[] flagNames) {
        boolean[] values = new boolean[flagNames.length];
        for (int i = 0; i < flagNames.length; i++) {
            Boolean value = ParsingPackageUtils.getAconfigFlags().getFlagValue(flagNames[i]);
            if (value == null) {
                Log.w("ApkAssets", "Couldn't find flag value for native: " + flagNames[i]);
            } else {
                values[i] = value;
            }
        }
        return values;
    }

    private static native long nativeLoad(@FormatType int format, @NonNull String path,
            @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException;
    private static native long nativeLoadEmpty(@PropertyFlags int flags,
+1 −0
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ cc_library_shared_for_libandroid_runtime {
    ],

    static_libs: [
        "android.content.res.flags-aconfig-cc-host-ro",
        "libziparchive_for_incfs",
        "libguiflags",
    ],
+65 −10
Original line number Diff line number Diff line
@@ -55,6 +55,12 @@ static struct assetsprovider_offsets_t {
  jmethodID toString;
} gAssetsProviderOffsets;

static struct apkassets_offsets_t {
    jclass classObject;
    jclass stringClassObject;
    jmethodID getFlagValues;
} gApkAssetsOffsets;

static struct {
  jmethodID detachFd;
} gParcelFileDescriptorOffsets;
@@ -219,6 +225,41 @@ class LoaderAssetsProvider : public AssetsProvider {
  std::string debug_name_;
};

static void GetFlagValues(JNIEnv* env, FlagMap& flag_map) {
    if (flag_map.empty()) {
        return;
    }
    jobjectArray flag_names =
            env->NewObjectArray(flag_map.size(), gApkAssetsOffsets.stringClassObject, nullptr);
    if (flag_names == nullptr) {
        ALOGE("ApkAssets: Getting flag values failed due to jni error, unable to create name "
              "array");
    }
    size_t i = 0;
    for (const auto& [flag_name, _] : flag_map) {
        jstring jstr = env->NewStringUTF(flag_name.c_str());
        env->SetObjectArrayElement(flag_names, i++, jstr);
        env->DeleteLocalRef(jstr);
    }
    jbooleanArray jflag_values = static_cast<jbooleanArray>(
            env->CallStaticObjectMethod(gApkAssetsOffsets.classObject,
                                        gApkAssetsOffsets.getFlagValues, flag_names));
    jboolean* flag_values = env->GetBooleanArrayElements(jflag_values, nullptr);
    if (flag_values == NULL) {
        ALOGE("ApkAssets: Getting flag values failed due to jni error");
    } else {
        i = 0;
        for (auto& [_, flag_value] : flag_map) {
            flag_value = flag_values[i++] != JNI_FALSE ? LoadedArscFlagStatus::Enabled
                                                       : LoadedArscFlagStatus::Disabled;
        }
    }

    if (jflag_values != nullptr) {
        env->ReleaseBooleanArrayElements(jflag_values, flag_values, 0);
    }
}

static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t format,
                        jstring java_path, const jint property_flags, jobject assets_provider) {
  ScopedUtfChars path(env, java_path);
@@ -228,6 +269,8 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma

  ATRACE_NAME(base::StringPrintf("LoadApkAssets(%s)", path.c_str()).c_str());

  auto flag_func = [=](FlagMap& map) { return GetFlagValues(env, map); };

  auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
  AssetManager2::ApkAssetsPtr apk_assets;
  switch (format) {
@@ -235,7 +278,7 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma
        auto assets = AssetsProvider::CreateWithOverride(ZipAssetsProvider::Create(path.c_str(),
                                                                                   property_flags),
                                                         std::move(loader_assets));
        apk_assets = ApkAssets::Load(std::move(assets), property_flags);
        apk_assets = ApkAssets::Load(std::move(assets), flag_func, property_flags);
        break;
    }
    case FORMAT_IDMAP:
@@ -245,13 +288,13 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma
        apk_assets =
                ApkAssets::LoadTable(AssetsProvider::CreateAssetFromFile(path.c_str()),
                                     AssetsProvider::CreateFromNullable(std::move(loader_assets)),
                                     property_flags);
                                     flag_func, property_flags);
        break;
    case FORMAT_DIRECTORY: {
        auto assets =
                AssetsProvider::CreateWithOverride(DirectoryAssetsProvider::Create(path.c_str()),
                                                   std::move(loader_assets));
        apk_assets = ApkAssets::Load(std::move(assets), property_flags);
        apk_assets = ApkAssets::Load(std::move(assets), flag_func, property_flags);
        break;
    }
    default:
@@ -314,7 +357,9 @@ static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, const format_type_t
                                                                                     .c_str(),
                                                                             property_flags),
                                                   std::move(loader_assets));
        apk_assets = ApkAssets::Load(std::move(assets), property_flags);
        apk_assets = ApkAssets::Load(
                std::move(assets), [=](FlagMap& map) { return GetFlagValues(env, map); },
                property_flags);
        break;
    }
    case FORMAT_ARSC:
@@ -322,7 +367,7 @@ static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, const format_type_t
                ApkAssets::LoadTable(AssetsProvider::CreateAssetFromFd(std::move(dup_fd),
                                                                       nullptr /* path */),
                                     AssetsProvider::CreateFromNullable(std::move(loader_assets)),
                                     property_flags);
                                     nullptr, property_flags);
        break;
    default:
      const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
@@ -388,7 +433,9 @@ static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_
                                                                             static_cast<off64_t>(
                                                                                     length)),
                                                   std::move(loader_assets));
        apk_assets = ApkAssets::Load(std::move(assets), property_flags);
        apk_assets = ApkAssets::Load(
                std::move(assets), [=](FlagMap& map) { return GetFlagValues(env, map); },
                property_flags);
        break;
    }
    case FORMAT_ARSC:
@@ -399,7 +446,7 @@ static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_
                                                                       static_cast<off64_t>(
                                                                               length)),
                                     AssetsProvider::CreateFromNullable(std::move(loader_assets)),
                                     property_flags);
                                     nullptr, property_flags);
        break;
    default:
      const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
@@ -417,9 +464,9 @@ static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_
}

static jlong NativeLoadEmpty(JNIEnv* env, jclass /*clazz*/, jint flags, jobject assets_provider) {
    auto apk_assets = ApkAssets::Load(AssetsProvider::CreateFromNullable(
                                              LoaderAssetsProvider::Create(env, assets_provider)),
                                      flags);
    auto apk_assets = ApkAssets::Load(
            AssetsProvider::CreateFromNullable(LoaderAssetsProvider::Create(env, assets_provider)),
            [=](FlagMap& map) { return GetFlagValues(env, map); }, flags);
    if (apk_assets == nullptr) {
        const std::string error_msg =
                base::StringPrintf("Failed to load empty assets with provider %p",
@@ -599,6 +646,14 @@ int register_android_content_res_ApkAssets(JNIEnv* env) {

  jclass parcelFd = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
  gParcelFileDescriptorOffsets.detachFd = GetMethodIDOrDie(env, parcelFd, "detachFd", "()I");

  gApkAssetsOffsets.classObject = FindClassOrDie(env, "android/content/res/ApkAssets");
  gApkAssetsOffsets.getFlagValues =
          GetStaticMethodIDOrDie(env, gApkAssetsOffsets.classObject, "getFlagValuesForNative",
                                 "([Ljava/lang/String;)[Z");
  gApkAssetsOffsets.stringClassObject =
          MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/String"));

  return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
                              arraysize(gApkAssetsMethods));
}
Loading