Merge "Fix tests affected by sparse.apk"

This commit is contained in:
Brandon Liu
2022-11-14 18:22:49 +00:00
committed by Android (Google) Code Review
12 changed files with 195 additions and 107 deletions

View File

@@ -211,6 +211,8 @@ cc_test {
"tests/data/**/*.apk",
"tests/data/**/*.arsc",
"tests/data/**/*.idmap",
":FrameworkResourcesSparseTestApp",
":FrameworkResourcesNotSparseTestApp",
],
test_suites: ["device-tests"],
}

View File

@@ -71,62 +71,6 @@ TEST(LoadedArscTest, LoadSinglePackageArsc) {
ASSERT_TRUE(LoadedPackage::GetEntry(type.type, entry_index).has_value());
}
TEST(LoadedArscTest, LoadSparseEntryApp) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9));
ASSERT_THAT(package, NotNull());
const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1;
const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9);
const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_entries.size(), Ge(1u));
auto type = type_spec->type_entries[0];
ASSERT_TRUE(LoadedPackage::GetEntry(type.type, entry_index).has_value());
}
TEST(LoadedArscTest, FindSparseEntryApp) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
loaded_arsc->GetPackageById(get_package_id(sparse::R::string::only_v26));
ASSERT_THAT(package, NotNull());
const uint8_t type_index = get_type_id(sparse::R::string::only_v26) - 1;
const uint16_t entry_index = get_entry_id(sparse::R::string::only_v26);
const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_entries.size(), Ge(1u));
// Ensure that AAPT2 sparsely encoded the v26 config as expected.
auto type_entry = std::find_if(
type_spec->type_entries.begin(), type_spec->type_entries.end(),
[](const TypeSpec::TypeEntry& x) { return x.config.sdkVersion == 26; });
ASSERT_NE(type_entry, type_spec->type_entries.end());
ASSERT_NE(type_entry->type->flags & ResTable_type::FLAG_SPARSE, 0);
// Test fetching a resource with only sparsely encoded configs by name.
auto id = package->FindEntryByName(u"string", u"only_v26");
ASSERT_EQ(id.value(), fix_package_id(sparse::R::string::only_v26, 0));
}
TEST(LoadedArscTest, LoadSharedLibrary) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
@@ -404,4 +348,84 @@ TEST(LoadedArscTest, LoadCustomLoader) {
// sizeof(Res_value) might not be backwards compatible.
// TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
class LoadedArscParameterizedTest :
public testing::TestWithParam<std::string> {
};
TEST_P(LoadedArscParameterizedTest, LoadSparseEntryApp) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetParam(), "resources.arsc", &contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9));
ASSERT_THAT(package, NotNull());
const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1;
const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9);
const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_entries.size(), Ge(1u));
auto type = type_spec->type_entries[0];
ASSERT_TRUE(LoadedPackage::GetEntry(type.type, entry_index).has_value());
}
TEST_P(LoadedArscParameterizedTest, FindSparseEntryApp) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetParam(), "resources.arsc", &contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
loaded_arsc->GetPackageById(get_package_id(sparse::R::string::only_land));
ASSERT_THAT(package, NotNull());
const uint8_t type_index = get_type_id(sparse::R::string::only_land) - 1;
const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_entries.size(), Ge(1u));
// Type Entry with default orientation is not sparse encoded because the ratio of
// populated entries to total entries is above threshold.
// Only find out default locale because Soong build system will introduce pseudo
// locales for the apk generated at runtime.
auto type_entry_default = std::find_if(
type_spec->type_entries.begin(), type_spec->type_entries.end(),
[] (const TypeSpec::TypeEntry& x) { return x.config.orientation == 0 &&
x.config.locale == 0; });
ASSERT_NE(type_entry_default, type_spec->type_entries.end());
ASSERT_EQ(type_entry_default->type->flags & ResTable_type::FLAG_SPARSE, 0);
// Type Entry with land orientation is sparse encoded as expected.
// Only find out default locale because Soong build system will introduce pseudo
// locales for the apk generated at runtime.
auto type_entry_land = std::find_if(
type_spec->type_entries.begin(), type_spec->type_entries.end(),
[](const TypeSpec::TypeEntry& x) { return x.config.orientation ==
ResTable_config::ORIENTATION_LAND &&
x.config.locale == 0; });
ASSERT_NE(type_entry_land, type_spec->type_entries.end());
ASSERT_NE(type_entry_land->type->flags & ResTable_type::FLAG_SPARSE, 0);
// Test fetching a resource with only sparsely encoded configs by name.
auto id = package->FindEntryByName(u"string", u"only_land");
ASSERT_EQ(id.value(), fix_package_id(sparse::R::string::only_land, 0));
}
INSTANTIATE_TEST_SUITE_P(
FrameWorkResourcesLoadedArscTests,
LoadedArscParameterizedTest,
::testing::Values(
base::GetExecutableDirectory() + "/tests/data/sparse/sparse.apk",
base::GetExecutableDirectory() + "/FrameworkResourcesSparseTestApp.apk"
));
} // namespace android

View File

@@ -15,6 +15,7 @@
*/
#include "androidfw/ResourceTypes.h"
#include "android-base/file.h"
#include <codecvt>
#include <locale>
@@ -41,34 +42,6 @@ TEST(ResTableTest, ShouldLoadSuccessfully) {
ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
}
TEST(ResTableTest, ShouldLoadSparseEntriesSuccessfully) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
&contents));
ResTable table;
ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
table.setParameters(&config);
String16 name(u"com.android.sparse:integer/foo_9");
uint32_t flags;
uint32_t resid =
table.identifierForName(name.string(), name.size(), nullptr, 0, nullptr, 0, &flags);
ASSERT_NE(0u, resid);
Res_value val;
ResTable_config selected_config;
ASSERT_GE(
table.getResource(resid, &val, false /*mayBeBag*/, 0u /*density*/, &flags, &selected_config),
0);
EXPECT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
EXPECT_EQ(900u, val.data);
}
TEST(ResTableTest, SimpleTypeIsRetrievedCorrectly) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
@@ -476,4 +449,43 @@ TEST(ResTableTest, TruncatedEncodeLength) {
ASSERT_FALSE(invalid_pool->stringAt(invalid_val.data).has_value());
}
class ResTableParameterizedTest :
public testing::TestWithParam<std::string> {
};
TEST_P(ResTableParameterizedTest, ShouldLoadSparseEntriesSuccessfully) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetParam(), "resources.arsc", &contents));
ResTable table;
ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
ResTable_config config;
memset(&config, 0, sizeof(config));
config.orientation = ResTable_config::ORIENTATION_LAND;
table.setParameters(&config);
String16 name(u"com.android.sparse:integer/foo_9");
uint32_t flags;
uint32_t resid =
table.identifierForName(name.string(), name.size(), nullptr, 0, nullptr, 0, &flags);
ASSERT_NE(0u, resid);
Res_value val;
ResTable_config selected_config;
ASSERT_GE(
table.getResource(resid, &val, false /*mayBeBag*/, 0u /*density*/, &flags, &selected_config),
0);
EXPECT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
EXPECT_EQ(900u, val.data);
}
INSTANTIATE_TEST_SUITE_P(
FrameWorkResourcesResTableTests,
ResTableParameterizedTest,
::testing::Values(
base::GetExecutableDirectory() + "/tests/data/sparse/sparse.apk",
base::GetExecutableDirectory() + "/FrameworkResourcesSparseTestApp.apk"
));
} // namespace android

View File

@@ -16,6 +16,7 @@
#include "androidfw/AssetManager.h"
#include "androidfw/ResourceTypes.h"
#include "android-base/file.h"
#include "BenchmarkHelpers.h"
#include "data/sparse/R.h"
@@ -24,40 +25,74 @@ namespace sparse = com::android::sparse;
namespace android {
static void BM_SparseEntryGetResourceHelper(const std::vector<std::string>& paths,
uint32_t resid, benchmark::State& state, void (*GetResourceBenchmarkFunc)(
const std::vector<std::string>&, const ResTable_config*,
uint32_t, benchmark::State&)){
ResTable_config config;
memset(&config, 0, sizeof(config));
config.orientation = ResTable_config::ORIENTATION_LAND;
GetResourceBenchmarkFunc(paths, &config, resid, state);
}
static void BM_SparseEntryGetResourceOldSparse(benchmark::State& state, uint32_t resid) {
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/sparse.apk"}, &config, resid, state);
BM_SparseEntryGetResourceHelper({GetTestDataPath() + "/sparse/sparse.apk"}, resid,
state, &GetResourceBenchmarkOld);
}
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparse, Small, sparse::R::integer::foo_9);
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparse, Large, sparse::R::string::foo_999);
static void BM_SparseEntryGetResourceOldNotSparse(benchmark::State& state, uint32_t resid) {
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/not_sparse.apk"}, &config, resid, state);
BM_SparseEntryGetResourceHelper({GetTestDataPath() + "/sparse/not_sparse.apk"}, resid,
state, &GetResourceBenchmarkOld);
}
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparse, Small, sparse::R::integer::foo_9);
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparse, Large, sparse::R::string::foo_999);
static void BM_SparseEntryGetResourceSparse(benchmark::State& state, uint32_t resid) {
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
GetResourceBenchmark({GetTestDataPath() + "/sparse/sparse.apk"}, &config, resid, state);
BM_SparseEntryGetResourceHelper({GetTestDataPath() + "/sparse/sparse.apk"}, resid,
state, &GetResourceBenchmark);
}
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparse, Small, sparse::R::integer::foo_9);
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparse, Large, sparse::R::string::foo_999);
static void BM_SparseEntryGetResourceNotSparse(benchmark::State& state, uint32_t resid) {
ResTable_config config;
memset(&config, 0, sizeof(config));
config.sdkVersion = 26;
GetResourceBenchmark({GetTestDataPath() + "/sparse/not_sparse.apk"}, &config, resid, state);
BM_SparseEntryGetResourceHelper({GetTestDataPath() + "/sparse/not_sparse.apk"}, resid,
state, &GetResourceBenchmark);
}
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparse, Small, sparse::R::integer::foo_9);
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparse, Large, sparse::R::string::foo_999);
static void BM_SparseEntryGetResourceOldSparseRuntime(benchmark::State& state, uint32_t resid) {
BM_SparseEntryGetResourceHelper({base::GetExecutableDirectory() +
"/FrameworkResourcesSparseTestApp.apk"}, resid, state,
&GetResourceBenchmarkOld);
}
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparseRuntime, Small, sparse::R::integer::foo_9);
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparseRuntime, Large, sparse::R::string::foo_999);
static void BM_SparseEntryGetResourceOldNotSparseRuntime(benchmark::State& state, uint32_t resid) {
BM_SparseEntryGetResourceHelper({base::GetExecutableDirectory() +
"/FrameworkResourcesNotSparseTestApp.apk"}, resid, state,
&GetResourceBenchmarkOld);
}
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparseRuntime, Small, sparse::R::integer::foo_9);
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparseRuntime, Large, sparse::R::string::foo_999);
static void BM_SparseEntryGetResourceSparseRuntime(benchmark::State& state, uint32_t resid) {
BM_SparseEntryGetResourceHelper({base::GetExecutableDirectory() +
"/FrameworkResourcesSparseTestApp.apk"}, resid, state,
&GetResourceBenchmark);
}
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparseRuntime, Small, sparse::R::integer::foo_9);
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparseRuntime, Large, sparse::R::string::foo_999);
static void BM_SparseEntryGetResourceNotSparseRuntime(benchmark::State& state, uint32_t resid) {
BM_SparseEntryGetResourceHelper({base::GetExecutableDirectory() +
"/FrameworkResourcesNotSparseTestApp.apk"}, resid, state,
&GetResourceBenchmark);
}
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparseRuntime, Small, sparse::R::integer::foo_9);
BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparseRuntime, Large, sparse::R::string::foo_999);
} // namespace android

View File

@@ -0,0 +1,14 @@
android_test_helper_app {
name: "FrameworkResourcesSparseTestApp",
sdk_version: "current",
min_sdk_version: "32",
aaptflags: [
"--enable-sparse-encoding",
],
}
android_test_helper_app {
name: "FrameworkResourcesNotSparseTestApp",
sdk_version: "current",
min_sdk_version: "32",
}

View File

@@ -17,4 +17,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.sparse">
<application />
<uses-sdk android:minSdkVersion="32" />
</manifest>

View File

@@ -42,7 +42,7 @@ struct R {
struct string {
enum : uint32_t {
foo_999 = 0x7f0203e7,
only_v26 = 0x7f0203e8
only_land = 0x7f0203e8
};
};
};

View File

@@ -1,20 +1,20 @@
#!/bin/bash
OUTPUT_default=res/values/strings.xml
OUTPUT_v26=res/values-v26/strings.xml
OUTPUT_land=res/values-land/strings.xml
echo "<resources>" > $OUTPUT_default
echo "<resources>" > $OUTPUT_v26
echo "<resources>" > $OUTPUT_land
for i in {0..999}
do
echo " <string name=\"foo_$i\">$i</string>" >> $OUTPUT_default
if [ "$(($i % 3))" -eq "0" ]
then
echo " <string name=\"foo_$i\">$(($i * 10))</string>" >> $OUTPUT_v26
echo " <string name=\"foo_$i\">$(($i * 10))</string>" >> $OUTPUT_land
fi
done
echo "</resources>" >> $OUTPUT_default
echo " <string name=\"only_v26\">only v26</string>" >> $OUTPUT_v26
echo "</resources>" >> $OUTPUT_v26
echo " <string name=\"only_land\">only land</string>" >> $OUTPUT_land
echo "</resources>" >> $OUTPUT_land

View File

@@ -333,5 +333,5 @@
<string name="foo_993">9930</string>
<string name="foo_996">9960</string>
<string name="foo_999">9990</string>
<string name="only_v26">only v26</string>
<string name="only_land">only land</string>
</resources>