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

Commit 2e394224 authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

Enable CTS verification of overlayable API

Allows retrieval of a string representation of overlayable resources
that can be compared during CTS testing to verify that the overlayable
resources on device match the expected overlayable API.

Bug: 135052616
Test: libandroidfw_tests
Test: atest OverlayHostTest
Change-Id: I613f28c202a0904a917577f932d072111c1aa7bd
parent 68e6b3af
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -786,7 +786,7 @@ package android.content.res {

  public final class AssetManager implements java.lang.AutoCloseable {
    method @NonNull public String[] getApkPaths();
    method @Nullable public java.util.Map<java.lang.String,java.lang.String> getOverlayableMap(String);
    method @Nullable public String getOverlayablesToString(String);
  }

  public final class Configuration implements java.lang.Comparable<android.content.res.Configuration> android.os.Parcelable {
+14 −1
Original line number Diff line number Diff line
@@ -1376,7 +1376,6 @@ public final class AssetManager implements AutoCloseable {
    /**
     * @hide
     */
    @TestApi
    @GuardedBy("this")
    public @Nullable Map<String, String> getOverlayableMap(String packageName) {
        synchronized (this) {
@@ -1385,6 +1384,18 @@ public final class AssetManager implements AutoCloseable {
        }
    }

    /**
     * @hide
     */
    @TestApi
    @GuardedBy("this")
    public @Nullable String getOverlayablesToString(String packageName) {
        synchronized (this) {
            ensureValidLocked();
            return nativeGetOverlayablesToString(mObject, packageName);
        }
    }

    @GuardedBy("this")
    private void incRefsLocked(long id) {
        if (DEBUG_REFS) {
@@ -1504,6 +1515,8 @@ public final class AssetManager implements AutoCloseable {
    private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid();
    private static native @Nullable Map nativeGetOverlayableMap(long ptr,
            @NonNull String packageName);
    private static native @Nullable String nativeGetOverlayablesToString(long ptr,
            @NonNull String packageName);

    // Global debug native methods.
    /**
+18 −1
Original line number Diff line number Diff line
@@ -397,6 +397,21 @@ static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,
  return array_map;
}

static jstring NativeGetOverlayablesToString(JNIEnv* env, jclass /*clazz*/, jlong ptr,
                                             jstring package_name) {
  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
  const ScopedUtfChars package_name_utf8(env, package_name);
  CHECK(package_name_utf8.c_str() != nullptr);
  const std::string std_package_name(package_name_utf8.c_str());

  std::string result;
  if (!assetmanager->GetOverlayablesToString(std_package_name, &result)) {
    return nullptr;
  }

  return env->NewStringUTF(result.c_str());
}

#ifdef __ANDROID__ // Layoutlib does not support parcel
static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
                                          jlongArray out_offsets) {
@@ -1608,6 +1623,8 @@ static const JNINativeMethod gAssetManagerMethods[] = {
     (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
    {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
     (void*)NativeGetOverlayableMap},
    {"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
     (void*)NativeGetOverlayablesToString},

    // Global management/debug methods.
    {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
+57 −1
Original line number Diff line number Diff line
@@ -224,6 +224,62 @@ const std::unordered_map<std::string, std::string>*
  return &loaded_package->GetOverlayableMap();
}

bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_name,
                                            std::string* out) const {
  uint8_t package_id = 0U;
  for (const auto& apk_assets : apk_assets_) {
    const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
    if (loaded_arsc == nullptr) {
      continue;
    }

    const auto& loaded_packages = loaded_arsc->GetPackages();
    if (loaded_packages.empty()) {
      continue;
    }

    const auto& loaded_package = loaded_packages[0];
    if (loaded_package->GetPackageName() == package_name) {
      package_id = GetAssignedPackageId(loaded_package.get());
      break;
    }
  }

  if (package_id == 0U) {
    ANDROID_LOG(ERROR) << base::StringPrintf("No package with name '%s", package_name.data());
    return false;
  }

  const size_t idx = package_ids_[package_id];
  if (idx == 0xff) {
    return false;
  }

  std::string output;
  for (const ConfiguredPackage& package : package_groups_[idx].packages_) {
    const LoadedPackage* loaded_package = package.loaded_package_;
    for (auto it = loaded_package->begin(); it != loaded_package->end(); it++) {
      const OverlayableInfo* info = loaded_package->GetOverlayableInfo(*it);
      if (info != nullptr) {
        ResourceName res_name;
        if (!GetResourceName(*it, &res_name)) {
          ANDROID_LOG(ERROR) << base::StringPrintf(
              "Unable to retrieve name of overlayable resource 0x%08x", *it);
          return false;
        }

        const std::string name = ToFormattedResourceString(&res_name);
        output.append(base::StringPrintf(
            "resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
            name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
      }
    }
  }

  *out = std::move(output);
  return true;
}

void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
  const int diff = configuration_.diff(configuration);
  configuration_ = configuration;
@@ -1073,7 +1129,7 @@ void AssetManager2::InvalidateCaches(uint32_t diff) {
  }
}

uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) {
uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
  for (auto& package_group : package_groups_) {
    for (auto& package2 : package_group.packages_) {
      if (package2.loaded_package_ == package) {
+5 −1
Original line number Diff line number Diff line
@@ -124,6 +124,10 @@ class AssetManager2 {
  // This may be nullptr if the APK represented by `cookie` has no resource table.
  const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const;

  // Returns a string representation of the overlayable API of a package.
  bool GetOverlayablesToString(const android::StringPiece& package_name,
                               std::string* out) const;

  const std::unordered_map<std::string, std::string>*
    GetOverlayableMapForPackage(uint32_t package_id) const;

@@ -308,7 +312,7 @@ class AssetManager2 {
  const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids);

  // Retrieve the assigned package id of the package if loaded into this AssetManager
  uint8_t GetAssignedPackageId(const LoadedPackage* package);
  uint8_t GetAssignedPackageId(const LoadedPackage* package) const;

  // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
  // have a longer lifetime.
Loading