AssetManager2: Fix list function
List was skipping directories. Include them, and add tests to ensure
the order and precedence is correct.
Bug: 72511641
Test: make libandroidfw_tests
Test: atest CtsContentTestCases:AssetManagerTest
Change-Id: Iadf45883283d3e4aae93bd7c3343745912e34fa0
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index c623ca6..2334e03 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -403,38 +403,30 @@
return nullptr;
}
- std::vector<std::string> all_file_paths;
- {
- StringPiece normalized_path = path_utf8.c_str();
- if (normalized_path.data()[0] == '/') {
- normalized_path = normalized_path.substr(1);
- }
- std::string root_path = StringPrintf("assets/%s", normalized_path.data());
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- for (const ApkAssets* assets : assetmanager->GetApkAssets()) {
- assets->ForEachFile(root_path, [&](const StringPiece& file_path, FileType type) {
- if (type == FileType::kFileTypeRegular) {
- all_file_paths.push_back(file_path.to_string());
- }
- });
- }
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::unique_ptr<AssetDir> asset_dir =
+ assetmanager->OpenDir(path_utf8.c_str());
+ if (asset_dir == nullptr) {
+ jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
+ return nullptr;
}
- jobjectArray array = env->NewObjectArray(all_file_paths.size(), g_stringClass, nullptr);
+ const size_t file_count = asset_dir->getFileCount();
+
+ jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
if (array == nullptr) {
return nullptr;
}
- jsize index = 0;
- for (const std::string& file_path : all_file_paths) {
- jstring java_string = env->NewStringUTF(file_path.c_str());
+ for (size_t i = 0; i < file_count; i++) {
+ jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
// Check for errors creating the strings (if malformed or no memory).
if (env->ExceptionCheck()) {
return nullptr;
}
- env->SetObjectArrayElement(array, index++, java_string);
+ env->SetObjectArrayElement(array, i, java_string);
// If we have a large amount of string in our array, we might overflow the
// local reference table of the VM.
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index da0205d..60f8a18 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -231,12 +231,16 @@
while ((result = ::Next(cookie, &entry, &name)) == 0) {
StringPiece full_file_path(reinterpret_cast<const char*>(name.name), name.name_length);
StringPiece leaf_file_path = full_file_path.substr(root_path_full.size());
- auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
- if (iter != leaf_file_path.end()) {
- dirs.insert(
- leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string());
- } else if (!leaf_file_path.empty()) {
- f(leaf_file_path, kFileTypeRegular);
+
+ if (!leaf_file_path.empty()) {
+ auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
+ if (iter != leaf_file_path.end()) {
+ std::string dir =
+ leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string();
+ dirs.insert(std::move(dir));
+ } else {
+ f(leaf_file_path, kFileTypeRegular);
+ }
}
}
::EndIteration(cookie);
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index eaf79cb..7cac2b3 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -36,6 +36,10 @@
namespace lib_two = com::android::lib_two;
namespace libclient = com::android::libclient;
+using ::testing::Eq;
+using ::testing::NotNull;
+using ::testing::StrEq;
+
namespace android {
class AssetManager2Test : public ::testing::Test {
@@ -64,6 +68,9 @@
system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/);
ASSERT_NE(nullptr, system_assets_);
+
+ app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk");
+ ASSERT_THAT(app_assets_, NotNull());
}
protected:
@@ -75,6 +82,7 @@
std::unique_ptr<const ApkAssets> libclient_assets_;
std::unique_ptr<const ApkAssets> appaslib_assets_;
std::unique_ptr<const ApkAssets> system_assets_;
+ std::unique_ptr<const ApkAssets> app_assets_;
};
TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
@@ -465,8 +473,68 @@
assetmanager.GetResourceId("main", "layout", "com.android.basic"));
}
-TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {}
+TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get()});
-TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
+ std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
+ ASSERT_THAT(asset, NotNull());
+
+ const char* data = reinterpret_cast<const char*>(asset->getBuffer(false /*wordAligned*/));
+ ASSERT_THAT(data, NotNull());
+ EXPECT_THAT(std::string(data, asset->getLength()), StrEq("file\n"));
+}
+
+TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
+
+ std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
+ ASSERT_THAT(asset, NotNull());
+
+ const char* data = reinterpret_cast<const char*>(asset->getBuffer(false /*wordAligned*/));
+ ASSERT_THAT(data, NotNull());
+ EXPECT_THAT(std::string(data, asset->getLength()), StrEq("app override file\n"));
+}
+
+TEST_F(AssetManager2Test, OpenDir) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get()});
+
+ std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
+ ASSERT_THAT(asset_dir, NotNull());
+ ASSERT_THAT(asset_dir->getFileCount(), Eq(2u));
+
+ EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("file.txt")));
+ EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+
+ EXPECT_THAT(asset_dir->getFileName(1), Eq(String8("subdir")));
+ EXPECT_THAT(asset_dir->getFileType(1), Eq(FileType::kFileTypeDirectory));
+
+ asset_dir = assetmanager.OpenDir("subdir");
+ ASSERT_THAT(asset_dir, NotNull());
+ ASSERT_THAT(asset_dir->getFileCount(), Eq(1u));
+
+ EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("subdir_file.txt")));
+ EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+}
+
+TEST_F(AssetManager2Test, OpenDirFromManyApks) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
+
+ std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
+ ASSERT_THAT(asset_dir, NotNull());
+ ASSERT_THAT(asset_dir->getFileCount(), Eq(3u));
+
+ EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("app_file.txt")));
+ EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+
+ EXPECT_THAT(asset_dir->getFileName(1), Eq(String8("file.txt")));
+ EXPECT_THAT(asset_dir->getFileType(1), Eq(FileType::kFileTypeRegular));
+
+ EXPECT_THAT(asset_dir->getFileName(2), Eq(String8("subdir")));
+ EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory));
+}
} // namespace android
diff --git a/libs/androidfw/tests/data/app/app.apk b/libs/androidfw/tests/data/app/app.apk
index ccb0824..c8ad86d 100644
--- a/libs/androidfw/tests/data/app/app.apk
+++ b/libs/androidfw/tests/data/app/app.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/app/assets/app_file.txt b/libs/androidfw/tests/data/app/assets/app_file.txt
new file mode 100644
index 0000000..b214e06
--- /dev/null
+++ b/libs/androidfw/tests/data/app/assets/app_file.txt
@@ -0,0 +1 @@
+app file
diff --git a/libs/androidfw/tests/data/app/assets/file.txt b/libs/androidfw/tests/data/app/assets/file.txt
new file mode 100644
index 0000000..0811542
--- /dev/null
+++ b/libs/androidfw/tests/data/app/assets/file.txt
@@ -0,0 +1 @@
+app override file
diff --git a/libs/androidfw/tests/data/app/build b/libs/androidfw/tests/data/app/build
index d418158..09af842 100755
--- a/libs/androidfw/tests/data/app/build
+++ b/libs/androidfw/tests/data/app/build
@@ -17,4 +17,11 @@
set -e
-aapt package -I ../system/system.apk -M AndroidManifest.xml -S res -F app.apk -f
+aapt2 compile --dir res -o compiled.flata
+aapt2 link \
+ --manifest AndroidManifest.xml \
+ -I ../system/system.apk \
+ -A assets \
+ -o app.apk \
+ compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/system/assets/file.txt b/libs/androidfw/tests/data/system/assets/file.txt
new file mode 100644
index 0000000..f73f309
--- /dev/null
+++ b/libs/androidfw/tests/data/system/assets/file.txt
@@ -0,0 +1 @@
+file
diff --git a/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt b/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt
new file mode 100644
index 0000000..3f74eb6
--- /dev/null
+++ b/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt
@@ -0,0 +1 @@
+subdir file
diff --git a/libs/androidfw/tests/data/system/build b/libs/androidfw/tests/data/system/build
index bfbdf4c..b65145a 100755
--- a/libs/androidfw/tests/data/system/build
+++ b/libs/androidfw/tests/data/system/build
@@ -17,4 +17,6 @@
set -e
-aapt package -x -M AndroidManifest.xml -S res -F system.apk -f
+aapt2 compile --dir res -o compiled.flata
+aapt2 link --manifest AndroidManifest.xml -A assets -o system.apk compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
index b97bdb6..5f60d21 100644
--- a/libs/androidfw/tests/data/system/res/values-sv/values.xml
+++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml
@@ -15,6 +15,5 @@
-->
<resources>
- <public type="integer" name="number" id="0x01030000" />
<integer name="number">1</integer>
</resources>
diff --git a/libs/androidfw/tests/data/system/res/values/themes.xml b/libs/androidfw/tests/data/system/res/values/themes.xml
index 35d43c7..7893c94 100644
--- a/libs/androidfw/tests/data/system/res/values/themes.xml
+++ b/libs/androidfw/tests/data/system/res/values/themes.xml
@@ -18,6 +18,7 @@
<public name="background" type="attr" id="0x01010000"/>
<public name="foreground" type="attr" id="0x01010001"/>
<public name="Theme.One" type="style" id="0x01020000"/>
+ <public type="integer" name="number" id="0x01030000" />
<attr name="background" format="color|reference"/>
<attr name="foreground" format="color|reference"/>
diff --git a/libs/androidfw/tests/data/system/system.apk b/libs/androidfw/tests/data/system/system.apk
index 1299016..9045d6c 100644
--- a/libs/androidfw/tests/data/system/system.apk
+++ b/libs/androidfw/tests/data/system/system.apk
Binary files differ