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

Commit 7c3a8ff2 authored by Priyanka Advani (xWF)'s avatar Priyanka Advani (xWF) Committed by Android (Google) Code Review
Browse files

Revert "Have runtime load RES_TABLE_FLAGGED chunks"

Revert submission 35289414-420720496

Reason for revert: Droidmonitor created revert due to b/443350458. Will be verifying through ABTD before submission.

Fix: 443350458

Reverted changes: /q/submissionid:35289414-420720496

Bug: 420720496
Change-Id: I0fb678a97ded4cea6c0a27bee85a1ab674f7940a
parent c5f0c0ff
Loading
Loading
Loading
Loading
+5 −6
Original line number Diff line number Diff line
@@ -236,8 +236,8 @@ static void GetFlagValues(JNIEnv* env, FlagMap& flag_map) {
              "array");
    }
    size_t i = 0;
    for (const auto& [_, flag_info] : flag_map) {
        jstring jstr = env->NewStringUTF(flag_info.name.c_str());
    for (const auto& [flag_name, _] : flag_map) {
        jstring jstr = env->NewStringUTF(flag_name.c_str());
        env->SetObjectArrayElement(flag_names, i++, jstr);
        env->DeleteLocalRef(jstr);
    }
@@ -249,10 +249,9 @@ static void GetFlagValues(JNIEnv* env, FlagMap& flag_map) {
        ALOGE("ApkAssets: Getting flag values failed due to jni error");
    } else {
        i = 0;
        for (auto& [_, flag_info] : flag_map) {
            flag_info.status = flag_values[i++] != JNI_FALSE
                    ? LoadedArscFeatureFlagStatus::Enabled
                    : LoadedArscFeatureFlagStatus::Disabled;
        for (auto& [_, flag_value] : flag_map) {
            flag_value = flag_values[i++] != JNI_FALSE ? LoadedArscFlagStatus::Enabled
                                                       : LoadedArscFlagStatus::Disabled;
        }
    }

+37 −106
Original line number Diff line number Diff line
@@ -54,35 +54,24 @@ namespace {
struct TypeSpecBuilder {
  explicit TypeSpecBuilder(incfs::verified_map_ptr<ResTable_typeSpec> header) : header_(header) {
    type_entries.reserve(dtohs(header_->typesCount));
    flagged_type_entries.reserve(dtohs(header_->typesCount));
  }

  void AddType(incfs::verified_map_ptr<ResTable_type> type, bool flagged) {
    TypeSpec::TypeEntry& entry = flagged ? flagged_type_entries.emplace_back()
                                         : type_entries.emplace_back();
  void AddType(incfs::verified_map_ptr<ResTable_type> type) {
    TypeSpec::TypeEntry& entry = type_entries.emplace_back();
    entry.config.copyFromDtoH(type->config);
    entry.type = type;
  }

  TypeSpec Build() {
    // put flagged values at the beginning so they are chosen over non-flagged ones
    if (!flagged_type_entries.empty()) {
      flagged_type_entries.insert(flagged_type_entries.end(), type_entries.begin(),
                                  type_entries.end());
      flagged_type_entries.shrink_to_fit();
      return {header_, std::move(flagged_type_entries)};
    } else {
    type_entries.shrink_to_fit();
    return {header_, std::move(type_entries)};
  }
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TypeSpecBuilder);

  incfs::verified_map_ptr<ResTable_typeSpec> header_;
  std::vector<TypeSpec::TypeEntry> type_entries;
  std::vector<TypeSpec::TypeEntry> flagged_type_entries;
};

}  // namespace
@@ -467,36 +456,8 @@ const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const {
  return nullptr;
}

bool LoadType(
    const Chunk& chunk,
    std::unordered_map<int, std::optional<TypeSpecBuilder>>& type_builder_map,
    bool flagged) {
  const auto type = chunk.header<ResTable_type, kResTableTypeMinSize>();
  if (!type) {
    LOG(ERROR) << "RES_TABLE_TYPE_TYPE too small.";
    return false;
  }

  if (!VerifyResTableType(type)) {
    return false;
  }

  // Type chunks must be preceded by their TypeSpec chunks.
  auto& maybe_type_builder = type_builder_map[type->id];
  if (maybe_type_builder) {
    maybe_type_builder->AddType(type.verified(), flagged);
  } else {
    LOG(ERROR) << StringPrintf(
        "RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.",
        type->id);
    return false;
  }
  return true;
}

std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
                                                         package_property_t property_flags,
                                                         const FlagMap& flag_map) {
                                                         package_property_t property_flags) {
  ATRACE_NAME("LoadedPackage::Load");
  const bool optimize_name_lookups = (property_flags & PROPERTY_OPTIMIZE_NAME_LOOKUPS) != 0;
  std::unique_ptr<LoadedPackage> loaded_package(new LoadedPackage(optimize_name_lookups));
@@ -632,49 +593,28 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
      } break;

      case RES_TABLE_TYPE_TYPE: {
        if (!LoadType(child_chunk, type_builder_map, false)) {
        const auto type = child_chunk.header<ResTable_type, kResTableTypeMinSize>();
        if (!type) {
          LOG(ERROR) << "RES_TABLE_TYPE_TYPE too small.";
          return {};
        }
      } break;

      case RES_TABLE_FLAGGED: {
        if (android_content_res_resource_readwrite_flags()) {
          const auto flagged = child_chunk.header<ResTable_flagged>();
          if (!flagged) {
            LOG(ERROR) << "RES_TABLE_FLAGGED too small.";
        if (!VerifyResTableType(type)) {
          return {};
        }


          auto it = flag_map.find(flagged->flag_name_index.index);
          if (it == flag_map.end()) {
        // Type chunks must be preceded by their TypeSpec chunks.
        auto& maybe_type_builder = type_builder_map[type->id];
        if (maybe_type_builder) {
          maybe_type_builder->AddType(type.verified());
        } else {
          LOG(ERROR) << StringPrintf(
                "RES_TABLE_FLAGGED sections contains flag with index %d not in "
                "RES_TABLE_FLAG_LIST.",
                flagged->flag_name_index.index);
            return {};
          }
          if (ShouldIncludeFlaggedResource(it->second.status, flagged->flag_negated)) {
            ChunkIterator flagged_type_iter(child_chunk.data_ptr(), child_chunk.data_size());
            while (flagged_type_iter.HasNext()) {
              const Chunk flagged_child_chunk = flagged_type_iter.Next();

              switch (flagged_child_chunk.type()) {
                case RES_TABLE_TYPE_TYPE: {
                  if (!LoadType(flagged_child_chunk, type_builder_map, true)) {
              "RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.",
              type->id);
          return {};
        }
      } break;

                default:
                  LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
                  break;
              }
            }
          }
        }
      } break;

      case RES_TABLE_LIBRARY_TYPE: {
        const auto lib = child_chunk.header<ResTable_lib_header>();
        if (!lib) {
@@ -912,47 +852,29 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,

      case RES_TABLE_FLAG_LIST: {
        if (android_content_res_resource_readwrite_flags()) {
          if (!flag_map_.empty()) {
            LOG(WARNING) << "Multiple RES_TABLE_FLAG_LIST chunks found in RES_TABLE_TYPE, "
                            "skipping all but the first one.";
            break;
          }
          const auto& flag_header = child_chunk.header<ResTable_flag_list>();
          const auto names_begin = child_chunk.data_ptr().convert<uint32_t>();
          size_t count = child_chunk.data_size() / sizeof(names_begin.value());
          const auto names_end = names_begin + count;
          const auto start_index = child_chunk.data_ptr().convert<uint32_t>();
          size_t count = child_chunk.data_size() / sizeof(start_index.value());

          const auto end_index = start_index + count;
          if (count > 0 && global_string_pool_->size() == 0) {
            LOG(ERROR) << "RES_TABLE_FLAG_LIST with empty string pool";
            return false;
          }
          for (auto name_iter = names_begin; name_iter != names_end; ++name_iter) {
            if (!name_iter) {
          for (auto index = start_index; index != end_index; ++index) {
            if (!index) {
              LOG(ERROR) << "Couldn't read RES_TABLE_FLAG_LIST.";
              return false;
            }
            auto sp_index = dtohl(name_iter.value());
            auto sp_index = dtohl(index.value());
            auto flag_name = global_string_pool_->string8At(sp_index);
            if (flag_name) {
              flag_map_.insert({sp_index, FeatureFlagInfo {
                                              .name = std::string(flag_name.value()),
                                              .status = LoadedArscFeatureFlagStatus::Unknown
                                          }});
              flag_map_.insert({std::string(flag_name.value()), LoadedArscFlagStatus::Unknown});
            } else {
              LOG(ERROR) << "flag list: couldn't find flag name with index " << sp_index;
              return false;
            }
          }
          if (!flag_map_.empty()) {
            if (get_flag_values_func_) {
              get_flag_values_func_(flag_map_);
            } else {
              for (auto& [_, flag_info] : flag_map_) {
                flag_info.status = LoadedArscFeatureFlagStatus::AlwaysShown;
              }
            }
          }

        }
      }
      break;
@@ -966,7 +888,7 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
        packages_seen++;

        std::unique_ptr<const LoadedPackage> loaded_package =
            LoadedPackage::Load(child_chunk, property_flags, flag_map_);
            LoadedPackage::Load(child_chunk, property_flags);
        if (!loaded_package) {
          return false;
        }
@@ -983,6 +905,15 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
    }
  }

  if (!flag_map_.empty()) {
    if (get_flag_values_func_) {
      get_flag_values_func_(flag_map_);
    } else {
      for (auto& [_, flag_value] : flag_map_) {
        flag_value = LoadedArscFlagStatus::AlwaysShown;
      }
    }
  }

  if (iter.HadError()) {
    LOG(ERROR) << iter.GetLastError();
+14 −32
Original line number Diff line number Diff line
@@ -112,36 +112,6 @@ struct OverlayableInfo {
  uint32_t policy_flags;
};


// Possible statuses for android feature flags
enum class LoadedArscFeatureFlagStatus {
  // The flag is enabled and should be included only for non-negated conditions
  Enabled,
  // The flag is disabled and should be included only for negated conditions
  Disabled,
  // The flag should always be included regardless of whether the condition is negated or not
  AlwaysShown,
  // The flag should never be included regardless of whether the condition is negated or not
  AlwaysHidden,
  // The status of the flag is unknown
  Unknown
};

struct FeatureFlagInfo {
  std::string name;
  LoadedArscFeatureFlagStatus status;
};

inline bool ShouldIncludeFlaggedResource(LoadedArscFeatureFlagStatus status, bool flag_negated) {
  return (status == LoadedArscFeatureFlagStatus::AlwaysShown) ||
         ((status == LoadedArscFeatureFlagStatus::Enabled) && !flag_negated) ||
         ((status == LoadedArscFeatureFlagStatus::Disabled) && flag_negated);
};

// A map from flag name (as an index in the StringPool it's stored in) to enabled status, during
// resource loading we can check flag values to determine if values should be included
using FlagMap = std::unordered_map<size_t, FeatureFlagInfo>;

class LoadedPackage {
 public:
  class iterator {
@@ -194,8 +164,7 @@ class LoadedPackage {
  }

  static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
                                                   package_property_t property_flags,
                                                   const FlagMap& flag_map);
                                                   package_property_t property_flags);

  // Finds the entry with the specified type name and entry name. The names are in UTF-16 because
  // the underlying ResStringPool API expects this. For now this is acceptable, but since
@@ -344,6 +313,19 @@ class LoadedPackage {
  std::unordered_map<std::string, std::string> overlayable_map_;
};

// Possible statuses for android feature flags
enum class LoadedArscFlagStatus {
  Enabled,
  Disabled,
  AlwaysShown,
  AlwaysHidden,
  Unknown
};

// A map from flag name to enabled status, during resource loading we can check flag values to
// determine if values should be included
using FlagMap = std::unordered_map<std::string, LoadedArscFlagStatus>;

// A callback that take a flag map and populates the enabled status for each of the flags
using GetFlagValuesFunc = std::function<void(FlagMap&)>;