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

Commit 0f76311c authored by Mårten Kongstad's avatar Mårten Kongstad Committed by Todd Kennedy
Browse files

idmap2: replace std::pair<bool, T> with Result<T>

Introduce a new type Result<T> to indicate if an operation succeeded or
not, and if it did, to hold the return value of the operation. This is
the same as how std::pair<bool, T> is already used in the codebase, so
replace all instances with Result<T> to improve clarity.

Result<T> is simply an alias for std::optional<T>. The difference is
semantic: use Result<T> as the return value for functions that can fail,
use std::optional<T> when values are truly optional. This is modelled
after Rust's std::result and std::option.

A future change may graduate Result<T> to a proper class which can hold
additional details on why an operation failed, such as a string or an
error code. As a special case, continue to use std::unique_ptr<T>
instead of Result<std::unique_ptr<T>> for now: the latter would increase
code complexity without added benefit.

Test: make idmap2_tests
Change-Id: I2a8355107ed2b6485409e5e655a84cf1e20b9911
parent b57794af
Loading
Loading
Loading
Loading
+27 −28
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@

#include "idmap2/CommandLineOptions.h"
#include "idmap2/Idmap.h"
#include "idmap2/Result.h"
#include "idmap2/Xml.h"
#include "idmap2/ZipFile.h"

@@ -53,39 +54,40 @@ using android::base::StringPrintf;
using android::idmap2::CommandLineOptions;
using android::idmap2::IdmapHeader;
using android::idmap2::ResourceId;
using android::idmap2::Result;
using android::idmap2::Xml;
using android::idmap2::ZipFile;
using android::util::Utf16ToUtf8;

namespace {
std::pair<bool, ResourceId> WARN_UNUSED ParseResReference(const AssetManager2& am,
                                                          const std::string& res,

Result<ResourceId> WARN_UNUSED ParseResReference(const AssetManager2& am, const std::string& res,
                                                 const std::string& fallback_package) {
  // first, try to parse as a hex number
  char* endptr = nullptr;
  ResourceId resid;
  resid = strtol(res.c_str(), &endptr, 16);
  if (*endptr == '\0') {
    return std::make_pair(true, resid);
    return {resid};
  }

  // next, try to parse as a package:type/name string
  resid = am.GetResourceId(res, "", fallback_package);
  if (is_valid_resid(resid)) {
    return std::make_pair(true, resid);
    return {resid};
  }

  // end of the road: res could not be parsed
  return std::make_pair(false, 0);
  return {};
}

std::pair<bool, std::string> WARN_UNUSED GetValue(const AssetManager2& am, ResourceId resid) {
Result<std::string> WARN_UNUSED GetValue(const AssetManager2& am, ResourceId resid) {
  Res_value value;
  ResTable_config config;
  uint32_t flags;
  ApkAssetsCookie cookie = am.GetResource(resid, false, 0, &value, &config, &flags);
  if (cookie == kInvalidCookie) {
    return std::make_pair(false, "");
    return {};
  }

  std::string out;
@@ -123,31 +125,31 @@ std::pair<bool, std::string> WARN_UNUSED GetValue(const AssetManager2& am, Resou
      out.append(StringPrintf("dataType=0x%02x data=0x%08x", value.dataType, value.data));
      break;
  }
  return std::make_pair(true, out);
  return {out};
}

std::pair<bool, std::string> GetTargetPackageNameFromManifest(const std::string& apk_path) {
Result<std::string> GetTargetPackageNameFromManifest(const std::string& apk_path) {
  const auto zip = ZipFile::Open(apk_path);
  if (!zip) {
    return std::make_pair(false, "");
    return {};
  }
  const auto entry = zip->Uncompress("AndroidManifest.xml");
  if (!entry) {
    return std::make_pair(false, "");
    return {};
  }
  const auto xml = Xml::Create(entry->buf, entry->size);
  if (!xml) {
    return std::make_pair(false, "");
    return {};
  }
  const auto tag = xml->FindTag("overlay");
  if (!tag) {
    return std::make_pair(false, "");
    return {};
  }
  const auto iter = tag->find("targetPackage");
  if (iter == tag->end()) {
    return std::make_pair(false, "");
    return {};
  }
  return std::make_pair(true, iter->second);
  return {iter->second};
}
}  // namespace

@@ -195,14 +197,14 @@ bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) {
      }
      apk_assets.push_back(std::move(target_apk));

      bool lookup_ok;
      std::tie(lookup_ok, target_package_name) =
      const Result<std::string> package_name =
          GetTargetPackageNameFromManifest(idmap_header->GetOverlayPath().to_string());
      if (!lookup_ok) {
      if (!package_name) {
        out_error << "error: failed to parse android:targetPackage from overlay manifest"
                  << std::endl;
        return false;
      }
      target_package_name = *package_name;
    } else if (target_path != idmap_header->GetTargetPath()) {
      out_error << "error: different target APKs (expected target APK " << target_path << " but "
                << idmap_path << " has target APK " << idmap_header->GetTargetPath() << ")"
@@ -227,21 +229,18 @@ bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) {
  am.SetApkAssets(raw_pointer_apk_assets);
  am.SetConfiguration(config);

  ResourceId resid;
  bool lookup_ok;
  std::tie(lookup_ok, resid) = ParseResReference(am, resid_str, target_package_name);
  if (!lookup_ok) {
  const Result<ResourceId> resid = ParseResReference(am, resid_str, target_package_name);
  if (!resid) {
    out_error << "error: failed to parse resource ID" << std::endl;
    return false;
  }

  std::string value;
  std::tie(lookup_ok, value) = GetValue(am, resid);
  if (!lookup_ok) {
    out_error << StringPrintf("error: resource 0x%08x not found", resid) << std::endl;
  const Result<std::string> value = GetValue(am, *resid);
  if (!value) {
    out_error << StringPrintf("error: resource 0x%08x not found", *resid) << std::endl;
    return false;
  }
  std::cout << value << std::endl;
  std::cout << *value << std::endl;

  return true;
}
+2 −3
Original line number Diff line number Diff line
@@ -18,19 +18,18 @@
#define IDMAP2_INCLUDE_IDMAP2_RESOURCEUTILS_H_

#include <string>
#include <utility>

#include "android-base/macros.h"
#include "androidfw/AssetManager2.h"

#include "idmap2/Idmap.h"
#include "idmap2/Result.h"

namespace android {
namespace idmap2 {
namespace utils {

std::pair<bool, std::string> WARN_UNUSED ResToTypeEntryName(const AssetManager2& am,
                                                            ResourceId resid);
Result<std::string> WARN_UNUSED ResToTypeEntryName(const AssetManager2& am, ResourceId resid);

}  // namespace utils
}  // namespace idmap2
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

#ifndef IDMAP2_INCLUDE_IDMAP2_RESULT_H_
#define IDMAP2_INCLUDE_IDMAP2_RESULT_H_

#include <optional>

namespace android::idmap2 {

template <typename T>
using Result = std::optional<T>;

static constexpr std::nullopt_t kResultError = std::nullopt;

}  // namespace android::idmap2

#endif  // IDMAP2_INCLUDE_IDMAP2_RESULT_H_
+2 −2
Original line number Diff line number Diff line
@@ -19,10 +19,10 @@

#include <memory>
#include <string>
#include <utility>

#include "android-base/macros.h"
#include "ziparchive/zip_archive.h"
#include "idmap2/Result.h"

namespace android {
namespace idmap2 {
@@ -43,7 +43,7 @@ class ZipFile {
  static std::unique_ptr<const ZipFile> Open(const std::string& path);

  std::unique_ptr<const MemoryChunk> Uncompress(const std::string& entryPath) const;
  std::pair<bool, uint32_t> Crc(const std::string& entryPath) const;
  Result<uint32_t> Crc(const std::string& entryPath) const;

  ~ZipFile();

+22 −22
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@

#include "idmap2/Idmap.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/ZipFile.h"

namespace android {
@@ -143,18 +144,16 @@ bool IdmapHeader::IsUpToDate(std::ostream& out_error) const {
    return false;
  }

  bool status;
  uint32_t target_crc;
  std::tie(status, target_crc) = target_zip->Crc("resources.arsc");
  if (!status) {
  Result<uint32_t> target_crc = target_zip->Crc("resources.arsc");
  if (!target_crc) {
    out_error << "error: failed to get target crc" << std::endl;
    return false;
  }

  if (target_crc_ != target_crc) {
  if (target_crc_ != *target_crc) {
    out_error << base::StringPrintf(
                     "error: bad target crc: idmap version 0x%08x, file system version 0x%08x",
                     target_crc_, target_crc)
                     target_crc_, *target_crc)
              << std::endl;
    return false;
  }
@@ -165,17 +164,16 @@ bool IdmapHeader::IsUpToDate(std::ostream& out_error) const {
    return false;
  }

  uint32_t overlay_crc;
  std::tie(status, overlay_crc) = overlay_zip->Crc("resources.arsc");
  if (!status) {
  Result<uint32_t> overlay_crc = overlay_zip->Crc("resources.arsc");
  if (!overlay_crc) {
    out_error << "error: failed to get overlay crc" << std::endl;
    return false;
  }

  if (overlay_crc_ != overlay_crc) {
  if (overlay_crc_ != *overlay_crc) {
    out_error << base::StringPrintf(
                     "error: bad overlay crc: idmap version 0x%08x, file system version 0x%08x",
                     overlay_crc_, overlay_crc)
                     overlay_crc_, *overlay_crc)
              << std::endl;
    return false;
  }
@@ -322,17 +320,20 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_
  std::unique_ptr<IdmapHeader> header(new IdmapHeader());
  header->magic_ = kIdmapMagic;
  header->version_ = kIdmapCurrentVersion;
  bool crc_status;
  std::tie(crc_status, header->target_crc_) = target_zip->Crc("resources.arsc");
  if (!crc_status) {

  Result<uint32_t> crc = target_zip->Crc("resources.arsc");
  if (!crc) {
    out_error << "error: failed to get zip crc for target" << std::endl;
    return nullptr;
  }
  std::tie(crc_status, header->overlay_crc_) = overlay_zip->Crc("resources.arsc");
  if (!crc_status) {
  header->target_crc_ = *crc;

  crc = overlay_zip->Crc("resources.arsc");
  if (!crc) {
    out_error << "error: failed to get zip crc for overlay" << std::endl;
    return nullptr;
  }
  header->overlay_crc_ = *crc;

  if (target_apk_path.size() > sizeof(header->target_path_)) {
    out_error << "error: target apk path \"" << target_apk_path << "\" longer that maximum size "
@@ -358,15 +359,14 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_
  const auto end = overlay_pkg->end();
  for (auto iter = overlay_pkg->begin(); iter != end; ++iter) {
    const ResourceId overlay_resid = *iter;
    bool lookup_ok;
    std::string name;
    std::tie(lookup_ok, name) = utils::ResToTypeEntryName(overlay_asset_manager, overlay_resid);
    if (!lookup_ok) {
    Result<std::string> name = utils::ResToTypeEntryName(overlay_asset_manager, overlay_resid);
    if (!name) {
      continue;
    }
    // prepend "<package>:" to turn name into "<package>:<type>/<name>"
    name = base::StringPrintf("%s:%s", target_pkg->GetPackageName().c_str(), name.c_str());
    const ResourceId target_resid = NameToResid(target_asset_manager, name);
    const std::string full_name =
        base::StringPrintf("%s:%s", target_pkg->GetPackageName().c_str(), name->c_str());
    const ResourceId target_resid = NameToResid(target_asset_manager, full_name);
    if (target_resid == 0) {
      continue;
    }
Loading