summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt2/Debug.cpp10
-rw-r--r--tools/aapt2/ResourceParser.cpp2
-rw-r--r--tools/aapt2/ResourceTable.h7
-rw-r--r--tools/aapt2/ResourceUtils.cpp32
-rw-r--r--tools/aapt2/ResourceUtils.h4
-rw-r--r--tools/aapt2/ResourceUtils_test.cpp35
-rw-r--r--tools/aapt2/ResourceValues.cpp19
-rw-r--r--tools/aapt2/ResourceValues.h1
-rw-r--r--tools/aapt2/SdkConstants.cpp4
-rw-r--r--tools/aapt2/cmd/Compile.cpp1
-rw-r--r--tools/aapt2/cmd/Dump.cpp1
-rw-r--r--tools/aapt2/cmd/Link.cpp1
-rw-r--r--tools/aapt2/cmd/Link_test.cpp18
-rw-r--r--tools/aapt2/cmd/Optimize.cpp1
-rw-r--r--tools/aapt2/compile/IdAssigner.cpp39
-rw-r--r--tools/aapt2/compile/IdAssigner_test.cpp30
-rw-r--r--tools/aapt2/format/binary/TableFlattener.cpp7
-rw-r--r--tools/aapt2/format/proto/ProtoDeserialize.cpp2
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize_test.cpp5
-rw-r--r--tools/aapt2/link/ReferenceLinker.cpp4
-rw-r--r--tools/aapt2/link/XmlReferenceLinker.cpp3
-rw-r--r--tools/aapt2/optimize/Obfuscator_test.cpp10
-rw-r--r--tools/aapt2/process/SymbolTable.cpp15
-rw-r--r--tools/aapt2/process/SymbolTable.h2
-rw-r--r--tools/incident_section_gen/main.cpp2
-rw-r--r--tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt75
-rw-r--r--tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt6
-rw-r--r--tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt6
-rw-r--r--tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt7
-rw-r--r--tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt32
-rw-r--r--tools/protologtool/Android.bp2
-rw-r--r--tools/xmlpersistence/Android.bp20
-rw-r--r--tools/xmlpersistence/OWNERS1
-rw-r--r--tools/xmlpersistence/manifest.txt1
-rw-r--r--tools/xmlpersistence/src/main/kotlin/Generator.kt577
-rw-r--r--tools/xmlpersistence/src/main/kotlin/Main.kt45
-rw-r--r--tools/xmlpersistence/src/main/kotlin/Parser.kt248
-rw-r--r--tools/xmlpersistence/src/main/kotlin/StringCaseExtensions.kt44
38 files changed, 295 insertions, 1024 deletions
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index df878899fa28..cac4edd8db21 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -265,6 +265,16 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions&
ValueHeadlinePrinter headline_printer(package.name, printer);
ValueBodyPrinter body_printer(package.name, printer);
+ auto& dynamicRefTable = table.GetReferencedPackages();
+ if (!dynamicRefTable.empty()) {
+ printer->Println(StringPrintf("DynamicRefTable entryCount=%d", int(dynamicRefTable.size())));
+ printer->Indent();
+ for (auto&& [id, name] : dynamicRefTable) {
+ printer->Println(StringPrintf("0x%02x -> %s", id, name.c_str()));
+ }
+ printer->Undent();
+ }
+
printer->Print("Package name=");
printer->Print(package.name);
if (package.id) {
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index fa9a98f136cb..6af39b739e9b 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -800,7 +800,7 @@ std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub
// Process the raw value.
std::unique_ptr<Item> processed_item = ResourceUtils::TryParseItemForAttribute(
- xmlsub_tree.raw_value, type_mask, on_create_reference);
+ &diag, xmlsub_tree.raw_value, type_mask, on_create_reference);
if (processed_item) {
// Fix up the reference.
if (auto ref = ValueCast<Reference>(processed_item.get())) {
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index bb286a8abdaa..61e399c7ab68 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -307,6 +307,11 @@ class ResourceTable {
// order.
ResourceTableView GetPartitionedView(const ResourceTableViewOptions& options = {}) const;
+ using ReferencedPackages = std::map<uint8_t, std::string>;
+ const ReferencedPackages& GetReferencedPackages() const {
+ return included_packages_;
+ }
+
struct SearchResult {
ResourceTablePackage* package;
ResourceTableType* type;
@@ -342,7 +347,7 @@ class ResourceTable {
// Set of dynamic packages that this table may reference. Their package names get encoded
// into the resources.arsc along with their compile-time assigned IDs.
- std::map<size_t, std::string> included_packages_;
+ ReferencedPackages included_packages_;
private:
DISALLOW_COPY_AND_ASSIGN(ResourceTable);
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 5a118a902963..d358df98ada6 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -619,7 +619,7 @@ uint32_t AndroidTypeToAttributeTypeMask(uint16_t type) {
}
std::unique_ptr<Item> TryParseItemForAttribute(
- StringPiece value, uint32_t type_mask,
+ android::IDiagnostics* diag, StringPiece value, uint32_t type_mask,
const std::function<bool(const ResourceName&)>& on_create_reference) {
using android::ResTable_map;
@@ -670,8 +670,32 @@ std::unique_ptr<Item> TryParseItemForAttribute(
// Try parsing this as a float.
auto floating_point = TryParseFloat(value);
if (floating_point) {
+ // Only check if the parsed result lost precision when the parsed item is
+ // android::Res_value::TYPE_FLOAT and there is other possible types saved in type_mask, like
+ // ResTable_map::TYPE_INTEGER.
if (type_mask & AndroidTypeToAttributeTypeMask(floating_point->value.dataType)) {
- return std::move(floating_point);
+ const bool mayOnlyBeFloat = (type_mask & ~float_mask) == 0;
+ const bool parsedAsFloat = floating_point->value.dataType == android::Res_value::TYPE_FLOAT;
+ if (!mayOnlyBeFloat && parsedAsFloat) {
+ float f = reinterpret_cast<float&>(floating_point->value.data);
+ std::u16string str16 = android::util::Utf8ToUtf16(util::TrimWhitespace(value));
+ double d;
+ if (android::ResTable::stringToDouble(str16.data(), str16.size(), d)) {
+ // Parse as a float only if the difference between float and double parsed from the
+ // same string is smaller than 1, otherwise return as raw string.
+ if (fabs(f - d) < 1) {
+ return std::move(floating_point);
+ } else {
+ if (diag->IsVerbose()) {
+ diag->Note(android::DiagMessage()
+ << "precision lost greater than 1 while parsing float " << value
+ << ", return a raw string");
+ }
+ }
+ }
+ } else {
+ return std::move(floating_point);
+ }
}
}
}
@@ -683,12 +707,12 @@ std::unique_ptr<Item> TryParseItemForAttribute(
* allows.
*/
std::unique_ptr<Item> TryParseItemForAttribute(
- StringPiece str, const Attribute* attr,
+ android::IDiagnostics* diag, StringPiece str, const Attribute* attr,
const std::function<bool(const ResourceName&)>& on_create_reference) {
using android::ResTable_map;
const uint32_t type_mask = attr->type_mask;
- auto value = TryParseItemForAttribute(str, type_mask, on_create_reference);
+ auto value = TryParseItemForAttribute(diag, str, type_mask, on_create_reference);
if (value) {
return value;
}
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index f30f4acfec7a..50fc87900162 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -200,11 +200,11 @@ std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* enum_attr,
* reference to an ID that must be created (@+id/foo).
*/
std::unique_ptr<Item> TryParseItemForAttribute(
- android::StringPiece value, const Attribute* attr,
+ android::IDiagnostics* diag, android::StringPiece value, const Attribute* attr,
const std::function<bool(const ResourceName&)>& on_create_reference = {});
std::unique_ptr<Item> TryParseItemForAttribute(
- android::StringPiece value, uint32_t type_mask,
+ android::IDiagnostics* diag, android::StringPiece value, uint32_t type_mask,
const std::function<bool(const ResourceName&)>& on_create_reference = {});
uint32_t AndroidTypeToAttributeTypeMask(uint16_t type);
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 568871a4d66e..4cba04de72ee 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -217,17 +217,46 @@ TEST(ResourceUtilsTest, EmptyIsBinaryPrimitive) {
}
TEST(ResourceUtilsTest, ItemsWithWhitespaceAreParsedCorrectly) {
- EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(" 12\n ", ResTable_map::TYPE_INTEGER),
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(context->GetDiagnostics(), " 12\n ",
+ ResTable_map::TYPE_INTEGER),
Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_INT_DEC, 12u))));
- EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(" true\n ", ResTable_map::TYPE_BOOLEAN),
+ EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(context->GetDiagnostics(), " true\n ",
+ ResTable_map::TYPE_BOOLEAN),
Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_INT_BOOLEAN, 0xffffffffu))));
const float expected_float = 12.0f;
const uint32_t expected_float_flattened = *(uint32_t*)&expected_float;
- EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(" 12.0\n ", ResTable_map::TYPE_FLOAT),
+ EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(context->GetDiagnostics(), " 12.0\n ",
+ ResTable_map::TYPE_FLOAT),
Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
}
+TEST(ResourceUtilsTest, FloatAndBigIntegerParsedCorrectly) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ const float expected_float = 0.125f;
+ const uint32_t expected_float_flattened = *(uint32_t*)&expected_float;
+ EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(context->GetDiagnostics(), "0.125",
+ ResTable_map::TYPE_FLOAT),
+ Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
+
+ const float special_float = 1.0f;
+ const uint32_t special_float_flattened = *(uint32_t*)&special_float;
+ EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(context->GetDiagnostics(), "1.0",
+ ResTable_map::TYPE_FLOAT),
+ Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, special_float_flattened))));
+
+ EXPECT_EQ(ResourceUtils::TryParseItemForAttribute(context->GetDiagnostics(), "1099511627776",
+ ResTable_map::TYPE_INTEGER),
+ std::unique_ptr<Item>(nullptr));
+
+ const float big_float = 1099511627776.0f;
+ const uint32_t big_flattened = *(uint32_t*)&big_float;
+ EXPECT_THAT(ResourceUtils::TryParseItemForAttribute(context->GetDiagnostics(), "1099511627776",
+ ResTable_map::TYPE_FLOAT),
+ Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, big_flattened))));
+}
+
TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) {
EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q"), Eq(std::optional<int>(10000)));
EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q.fingerprint"), Eq(std::optional<int>(10000)));
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index a5754e0d168f..166b01bd9154 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -439,6 +439,21 @@ static std::string ComplexToString(uint32_t complex_value, bool fraction) {
return str;
}
+// This function is designed to using different specifier to print different floats,
+// which can print more accurate format rather than using %g only.
+const char* BinaryPrimitive::DecideFormat(float f) {
+ // if the float is either too big or too tiny, print it in scientific notation.
+ // eg: "10995116277760000000000" to 1.099512e+22, "0.00000000001" to 1.000000e-11
+ if (fabs(f) > std::numeric_limits<int64_t>::max() || fabs(f) < 1e-10) {
+ return "%e";
+ // Else if the number is an integer exactly, print it without trailing zeros.
+ // eg: "1099511627776" to 1099511627776
+ } else if (int64_t(f) == f) {
+ return "%.0f";
+ }
+ return "%g";
+}
+
void BinaryPrimitive::PrettyPrint(Printer* printer) const {
using ::android::Res_value;
switch (value.dataType) {
@@ -470,7 +485,9 @@ void BinaryPrimitive::PrettyPrint(Printer* printer) const {
break;
case Res_value::TYPE_FLOAT:
- printer->Print(StringPrintf("%g", *reinterpret_cast<const float*>(&value.data)));
+ float f;
+ f = *reinterpret_cast<const float*>(&value.data);
+ printer->Print(StringPrintf(DecideFormat(f), f));
break;
case Res_value::TYPE_DIMENSION:
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 6f9dccbd3bcc..5192c2be1f98 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -284,6 +284,7 @@ struct BinaryPrimitive : public TransformableItem<BinaryPrimitive, BaseItem<Bina
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
void Print(std::ostream* out) const override;
+ static const char* DecideFormat(float f);
void PrettyPrint(text::Printer* printer) const override;
};
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index a7c5479b56fd..a766bd437120 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -26,8 +26,8 @@ using android::StringPiece;
namespace aapt {
static ApiVersion sDevelopmentSdkLevel = 10000;
-static const auto sDevelopmentSdkCodeNames =
- std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake"});
+static const auto sDevelopmentSdkCodeNames = std::unordered_set<StringPiece>(
+ {"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake", "VanillaIceCream"});
static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
{0x021c, 1},
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 03f9715fb265..d2ea59958f69 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -597,6 +597,7 @@ class CompileContext : public IAaptContext {
void SetVerbose(bool val) {
verbose_ = val;
+ diagnostics_->SetVerbose(val);
}
bool IsVerbose() override {
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 71b08022f688..864af06f187e 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -112,6 +112,7 @@ class DumpContext : public IAaptContext {
void SetVerbose(bool val) {
verbose_ = val;
+ diagnostics_.SetVerbose(val);
}
int GetMinSdkVersion() override {
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 97404fc69af2..eb4e38c5f35f 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -148,6 +148,7 @@ class LinkContext : public IAaptContext {
void SetVerbose(bool val) {
verbose_ = val;
+ diagnostics_->SetVerbose(val);
}
int GetMinSdkVersion() override {
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 28fcc1a4800e..7096f5cc54e3 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -441,8 +441,8 @@ static void BuildNonFinalizedSDK(const std::string& apk_path, const std::string&
R"(<resources>
<public type="attr" name="finalized_res" id="0x01010001"/>
- <!-- S staged attributes (support staged resources in the same type id) -->
- <staging-public-group type="attr" first-id="0x01010050">
+ <!-- S staged attributes (Not support staged resources in the same type id) -->
+ <staging-public-group type="attr" first-id="0x01fc0050">
<public name="staged_s_res" />
</staging-public-group>
@@ -480,8 +480,8 @@ static void BuildFinalizedSDK(const std::string& apk_path, const std::string& ja
<public type="attr" name="staged_s2_res" id="0x01010003"/>
<public type="string" name="staged_s_string" id="0x01020000"/>
- <!-- S staged attributes (support staged resources in the same type id) -->
- <staging-public-group-final type="attr" first-id="0x01010050">
+ <!-- S staged attributes (Not support staged resources in the same type id) -->
+ <staging-public-group-final type="attr" first-id="0x01fc0050">
<public name="staged_s_res" />
</staging-public-group-final>
@@ -551,7 +551,7 @@ TEST_F(LinkTest, StagedAndroidApi) {
EXPECT_THAT(android_r_contents, HasSubstr("public static final int finalized_res=0x01010001;"));
EXPECT_THAT(
android_r_contents,
- HasSubstr("public static final int staged_s_res; static { staged_s_res=0x01010050; }"));
+ HasSubstr("public static final int staged_s_res; static { staged_s_res=0x01fc0050; }"));
EXPECT_THAT(
android_r_contents,
HasSubstr("public static final int staged_s_string; static { staged_s_string=0x01fd0080; }"));
@@ -575,7 +575,7 @@ TEST_F(LinkTest, StagedAndroidApi) {
android::AssetManager2 am;
auto android_asset = android::ApkAssets::Load(android_apk);
ASSERT_THAT(android_asset, NotNull());
- ASSERT_TRUE(am.SetApkAssets({android_asset.get()}));
+ ASSERT_TRUE(am.SetApkAssets({android_asset}));
auto result = am.GetResourceId("android:attr/finalized_res");
ASSERT_TRUE(result.has_value());
@@ -583,7 +583,7 @@ TEST_F(LinkTest, StagedAndroidApi) {
result = am.GetResourceId("android:attr/staged_s_res");
ASSERT_TRUE(result.has_value());
- EXPECT_THAT(*result, Eq(0x01010050));
+ EXPECT_THAT(*result, Eq(0x01fc0050));
result = am.GetResourceId("android:string/staged_s_string");
ASSERT_TRUE(result.has_value());
@@ -631,7 +631,7 @@ TEST_F(LinkTest, FinalizedAndroidApi) {
auto app_against_non_final = android::ApkAssets::Load(app_apk);
ASSERT_THAT(android_asset, NotNull());
ASSERT_THAT(app_against_non_final, NotNull());
- ASSERT_TRUE(am.SetApkAssets({android_asset.get(), app_against_non_final.get()}));
+ ASSERT_TRUE(am.SetApkAssets({android_asset, app_against_non_final}));
auto result = am.GetResourceId("android:attr/finalized_res");
ASSERT_TRUE(result.has_value());
@@ -667,7 +667,7 @@ TEST_F(LinkTest, FinalizedAndroidApi) {
auto app_against_final = android::ApkAssets::Load(app_apk_respin);
ASSERT_THAT(app_against_final, NotNull());
- ASSERT_TRUE(am.SetApkAssets({android_asset.get(), app_against_final.get()}));
+ ASSERT_TRUE(am.SetApkAssets({android_asset, app_against_final}));
{
auto style = am.GetBag(0x7f020000);
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index dbe79701bf5c..f045dad6d11a 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -101,6 +101,7 @@ class OptimizeContext : public IAaptContext {
void SetVerbose(bool val) {
verbose_ = val;
+ diagnostics_.SetVerbose(val);
}
void SetMinSdkVersion(int sdk_version) {
diff --git a/tools/aapt2/compile/IdAssigner.cpp b/tools/aapt2/compile/IdAssigner.cpp
index b3f98a9d3e30..5421abde3689 100644
--- a/tools/aapt2/compile/IdAssigner.cpp
+++ b/tools/aapt2/compile/IdAssigner.cpp
@@ -37,6 +37,7 @@ using Result = expected<T, std::string>;
template <typename Id, typename Key>
struct NextIdFinder {
+ std::map<Id, Key> pre_assigned_ids_;
explicit NextIdFinder(Id start_id = 0u) : next_id_(start_id){};
// Attempts to reserve an identifier for the specified key.
@@ -55,7 +56,6 @@ struct NextIdFinder {
Id next_id_;
bool next_id_called_ = false;
bool exhausted_ = false;
- std::map<Id, Key> pre_assigned_ids_;
typename std::map<Id, Key>::iterator next_preassigned_id_;
};
@@ -158,7 +158,7 @@ bool IdAssigner::Consume(IAaptContext* context, ResourceTable* table) {
}
if (assigned_id_map_) {
- // Reserve all the IDs mentioned in the stable ID map. That way we won't assig IDs that were
+ // Reserve all the IDs mentioned in the stable ID map. That way we won't assign IDs that were
// listed in the map if they don't exist in the table.
for (const auto& stable_id_entry : *assigned_id_map_) {
const ResourceName& pre_assigned_name = stable_id_entry.first;
@@ -191,6 +191,11 @@ bool IdAssigner::Consume(IAaptContext* context, ResourceTable* table) {
}
namespace {
+static const std::string_view staged_type_overlap_error =
+ "Staged public resource type IDs have conflict with non staged public resources type "
+ "IDs, please restart staged resource type ID assignment at 0xff in public-staging.xml "
+ "and also delete all the overlapping groups in public-final.xml";
+
template <typename Id, typename Key>
Result<Id> NextIdFinder<Id, Key>::ReserveId(Key key, Id id) {
CHECK(!next_id_called_) << "ReserveId cannot be called after NextId";
@@ -282,8 +287,20 @@ bool IdAssignerContext::ReserveId(const ResourceName& name, ResourceId id,
// another type.
auto assign_result = type_id_finder_.ReserveId(key, id.type_id());
if (!assign_result.has_value()) {
- diag->Error(android::DiagMessage() << "can't assign ID " << id << " to resource " << name
- << " because type " << assign_result.error());
+ auto pre_assigned_type = type_id_finder_.pre_assigned_ids_[id.type_id()].type;
+ bool pre_assigned_type_staged =
+ non_staged_type_ids_.find(pre_assigned_type) == non_staged_type_ids_.end();
+ auto hex_type_id = fmt::format("{:#04x}", (int)id.type_id());
+ bool current_type_staged = visibility.staged_api;
+ diag->Error(android::DiagMessage()
+ << "can't assign type ID " << hex_type_id << " to "
+ << (current_type_staged ? "staged type " : "non staged type ") << name.type.type
+ << " because this type ID have been assigned to "
+ << (pre_assigned_type_staged ? "staged type " : "non staged type ")
+ << pre_assigned_type);
+ if (pre_assigned_type_staged || current_type_staged) {
+ diag->Error(android::DiagMessage() << staged_type_overlap_error);
+ }
return false;
}
type = types_.emplace(key, TypeGroup(package_id_, id.type_id())).first;
@@ -298,6 +315,20 @@ bool IdAssignerContext::ReserveId(const ResourceName& name, ResourceId id,
<< " because type already has ID " << std::hex << (int)id.type_id());
return false;
}
+ } else {
+ // Ensure that staged public resources cannot have the same type name and type id with
+ // non staged public resources.
+ auto non_staged_type = non_staged_type_ids_.find(name.type.type);
+ if (non_staged_type != non_staged_type_ids_.end() && non_staged_type->second == id.type_id()) {
+ diag->Error(
+ android::DiagMessage()
+ << "can`t assign type ID " << fmt::format("{:#04x}", (int)id.type_id())
+ << " to staged type " << name.type.type << " because type ID "
+ << fmt::format("{:#04x}", (int)id.type_id())
+ << " already has been assigned to a non staged resource type with the same type name");
+ diag->Error(android::DiagMessage() << staged_type_overlap_error);
+ return false;
+ }
}
auto assign_result = type->second.ReserveId(name, id);
diff --git a/tools/aapt2/compile/IdAssigner_test.cpp b/tools/aapt2/compile/IdAssigner_test.cpp
index 8911dad39470..ce45b7c1df04 100644
--- a/tools/aapt2/compile/IdAssigner_test.cpp
+++ b/tools/aapt2/compile/IdAssigner_test.cpp
@@ -117,14 +117,28 @@ TEST_F(IdAssignerTests, FailWhenTypeHasTwoNonStagedIds) {
}
TEST_F(IdAssignerTests, FailWhenTypeHasTwoNonStagedIdsRegardlessOfStagedId) {
- auto table = test::ResourceTableBuilder()
- .AddSimple("android:attr/foo", ResourceId(0x01050000))
- .AddSimple("android:attr/bar", ResourceId(0x01ff0006))
- .Add(NewResourceBuilder("android:attr/staged_baz")
- .SetId(0x01ff0000)
- .SetVisibility({.staged_api = true})
- .Build())
- .Build();
+ auto table =
+ test::ResourceTableBuilder()
+ .AddSimple("android:attr/foo", ResourceId(0x01050000))
+ .AddSimple("android:attr/bar", ResourceId(0x01ff0006))
+ .Add(NewResourceBuilder("android:attr/staged_baz")
+ .SetId(0x01ff0000)
+ .SetVisibility({.staged_api = true, .level = Visibility::Level::kPublic})
+ .Build())
+ .Build();
+ IdAssigner assigner;
+ ASSERT_FALSE(assigner.Consume(context.get(), table.get()));
+}
+
+TEST_F(IdAssignerTests, FailWhenTypeHaveBothStagedAndNonStagedIds) {
+ auto table =
+ test::ResourceTableBuilder()
+ .AddSimple("android:attr/foo", ResourceId(0x01010000))
+ .Add(NewResourceBuilder("android:bool/staged_baz")
+ .SetId(0x01010001)
+ .SetVisibility({.staged_api = true, .level = Visibility::Level::kPublic})
+ .Build())
+ .Build();
IdAssigner assigner;
ASSERT_FALSE(assigner.Consume(context.get(), table.get()));
}
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 8c594ba553a0..a1953c6966af 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -68,9 +68,8 @@ struct OverlayableChunk {
class PackageFlattener {
public:
PackageFlattener(IAaptContext* context, const ResourceTablePackageView& package,
- const std::map<size_t, std::string>* shared_libs,
- SparseEntriesMode sparse_entries,
- bool compact_entries,
+ const ResourceTable::ReferencedPackages* shared_libs,
+ SparseEntriesMode sparse_entries, bool compact_entries,
bool collapse_key_stringpool,
const std::set<ResourceName>& name_collapse_exemptions,
bool deduplicate_entry_values)
@@ -548,7 +547,7 @@ class PackageFlattener {
IAaptContext* context_;
android::IDiagnostics* diag_;
const ResourceTablePackageView package_;
- const std::map<size_t, std::string>* shared_libs_;
+ const ResourceTable::ReferencedPackages* shared_libs_;
SparseEntriesMode sparse_entries_;
bool compact_entries_;
android::StringPool type_pool_;
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 09ef9bddd3bd..e1a3013c07bb 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -916,7 +916,7 @@ std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
} break;
case pb::Primitive::kIntDecimalValue: {
val.dataType = android::Res_value::TYPE_INT_DEC;
- val.data = static_cast<uint32_t>(pb_prim.int_decimal_value());
+ val.data = static_cast<int32_t>(pb_prim.int_decimal_value());
} break;
case pb::Primitive::kIntHexadecimalValue: {
val.dataType = android::Res_value::TYPE_INT_HEX;
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index afb83562b129..fa8860ff69eb 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -250,6 +250,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
}
TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
xml::Element element;
element.line_number = 22;
element.column_number = 23;
@@ -269,8 +270,8 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
attr.namespace_uri = xml::kSchemaAndroid;
attr.value = "23dp";
attr.compiled_attribute = xml::AaptAttribute(Attribute{}, ResourceId(0x01010000));
- attr.compiled_value =
- ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
+ attr.compiled_value = ResourceUtils::TryParseItemForAttribute(
+ context->GetDiagnostics(), attr.value, android::ResTable_map::TYPE_DIMENSION);
attr.compiled_value->SetSource(android::Source().WithLine(25));
element.attributes.push_back(std::move(attr));
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 9dadfb26a3f8..c69b32513167 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -164,8 +164,8 @@ std::unique_ptr<Item> ReferenceLinkerTransformer::TransformItem(const Reference*
std::unique_ptr<Item> ReferenceLinkerTransformer::ParseValueWithAttribute(
std::unique_ptr<Item> value, const Attribute* attr) {
if (RawString* raw_string = ValueCast<RawString>(value.get())) {
- std::unique_ptr<Item> transformed =
- ResourceUtils::TryParseItemForAttribute(*raw_string->value, attr);
+ std::unique_ptr<Item> transformed = ResourceUtils::TryParseItemForAttribute(
+ context_->GetDiagnostics(), *raw_string->value, attr);
// If we could not parse as any specific type, try a basic STRING.
if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) {
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index d2e9bd770a31..aec7ceb82c0f 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -90,7 +90,8 @@ class XmlVisitor : public xml::PackageAwareVisitor {
attribute = &attr.compiled_attribute.value().attribute;
}
- attr.compiled_value = ResourceUtils::TryParseItemForAttribute(attr.value, attribute);
+ attr.compiled_value = ResourceUtils::TryParseItemForAttribute(context_->GetDiagnostics(),
+ attr.value, attribute);
if (attr.compiled_value) {
// With a compiledValue, we must resolve the reference and assign it an ID.
attr.compiled_value->SetSource(source);
diff --git a/tools/aapt2/optimize/Obfuscator_test.cpp b/tools/aapt2/optimize/Obfuscator_test.cpp
index 940cf1096f92..b3a915c9b604 100644
--- a/tools/aapt2/optimize/Obfuscator_test.cpp
+++ b/tools/aapt2/optimize/Obfuscator_test.cpp
@@ -300,10 +300,11 @@ TEST(ObfuscatorTest, WriteObfuscationMapInProtocolBufferFormat) {
ASSERT_TRUE(obfuscator.Consume(test::ContextBuilder().Build().get(),
getProtocolBufferTableUnderTest().get()));
- obfuscator.WriteObfuscationMap("obfuscated_map.pb");
+ const auto map_path = testing::TempDir() + "/obfuscated_map.pb";
+ ASSERT_TRUE(obfuscator.WriteObfuscationMap(map_path));
std::string pbOut;
- android::base::ReadFileToString("obfuscated_map.pb", &pbOut, false /* follow_symlinks */);
+ ASSERT_TRUE(android::base::ReadFileToString(map_path, &pbOut, false /* follow_symlinks */));
EXPECT_THAT(pbOut, HasSubstr("drawable/xmlfile.xml"));
EXPECT_THAT(pbOut, HasSubstr("drawable/pngfile.png"));
EXPECT_THAT(pbOut, HasSubstr("mycolor"));
@@ -328,10 +329,11 @@ TEST(ObfuscatorTest, WriteObfuscatingMapWithNonEnabledOption) {
ASSERT_TRUE(obfuscator.Consume(test::ContextBuilder().Build().get(),
getProtocolBufferTableUnderTest().get()));
- obfuscator.WriteObfuscationMap("obfuscated_map.pb");
+ const auto map_path = testing::TempDir() + "/obfuscated_map.pb";
+ ASSERT_TRUE(obfuscator.WriteObfuscationMap(map_path));
std::string pbOut;
- android::base::ReadFileToString("obfuscated_map.pb", &pbOut, false /* follow_symlinks */);
+ ASSERT_TRUE(android::base::ReadFileToString(map_path, &pbOut, false /* follow_symlinks */));
ASSERT_THAT(pbOut, Eq(""));
}
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index bca62da447b0..d78baf9ffeb4 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -220,15 +220,9 @@ std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::FindByName(
bool AssetManagerSymbolSource::AddAssetPath(StringPiece path) {
TRACE_CALL();
- if (std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path.data())) {
+ if (auto apk = ApkAssets::Load(path.data())) {
apk_assets_.push_back(std::move(apk));
-
- std::vector<const ApkAssets*> apk_assets;
- for (const std::unique_ptr<const ApkAssets>& apk_asset : apk_assets_) {
- apk_assets.push_back(apk_asset.get());
- }
-
- asset_manager_.SetApkAssets(apk_assets);
+ asset_manager_.SetApkAssets(apk_assets_);
return true;
}
return false;
@@ -251,7 +245,7 @@ bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId,
return true;
}
- for (const std::unique_ptr<const ApkAssets>& assets : apk_assets_) {
+ for (auto&& assets : apk_assets_) {
for (const std::unique_ptr<const android::LoadedPackage>& loaded_package
: assets->GetLoadedArsc()->GetPackages()) {
if (package_name == loaded_package->GetPackageName() && loaded_package->IsDynamic()) {
@@ -266,10 +260,11 @@ bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId,
static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
android::AssetManager2& am, ResourceId id) {
using namespace android;
- if (am.GetApkAssets().empty()) {
+ if (am.GetApkAssetsCount() == 0) {
return {};
}
+ auto op = am.StartOperation();
auto bag_result = am.GetBag(id.id);
if (!bag_result.has_value()) {
return nullptr;
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index b09ff702ca58..36eb0bab6046 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -207,8 +207,8 @@ class AssetManagerSymbolSource : public ISymbolSource {
}
private:
+ std::vector<android::AssetManager2::ApkAssetsPtr> apk_assets_;
android::AssetManager2 asset_manager_;
- std::vector<std::unique_ptr<const android::ApkAssets>> apk_assets_;
DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource);
};
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index dd266ffe0f16..a2c1d6b4f784 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -383,13 +383,11 @@ static bool generatePrivacyFlags(const Descriptor* descriptor, const Destination
if (allDefaults) return false;
emptyline();
- int policyCount = 0;
printf("Privacy* %s[] = {\n", messageName.c_str());
for (size_t i=0; i<fieldsInOrder.size(); i++) {
const FieldDescriptor* field = fieldsInOrder[i];
if (hasDefaultFlags[i]) continue; // NOLINT(clang-analyzer-core.uninitialized.Branch)
printf(" &%s,\n", getFieldName(field).c_str());
- policyCount++;
}
printf(" NULL };\n");
emptyline();
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
index dcfbe953f955..e03d92ab44a0 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
@@ -72,5 +72,78 @@ val EXCLUDED_CPP_INTERFACES = listOf(
"Status",
"IThermalService",
"IPowerManager",
- "ITunerResourceManager"
+ "ITunerResourceManager",
+ // b/278147400
+ "IActivityManager",
+ "IUidObserver",
+ "IDrm",
+ "IVsyncCallback",
+ "IVsyncService",
+ "ICallback",
+ "IIPCTest",
+ "ISafeInterfaceTest",
+ "IGpuService",
+ "IConsumerListener",
+ "IGraphicBufferConsumer",
+ "ITransactionComposerListener",
+ "SensorEventConnection",
+ "SensorServer",
+ "ICamera",
+ "ICameraClient",
+ "ICameraRecordingProxy",
+ "ICameraRecordingProxyListener",
+ "ICrypto",
+ "IOMXObserver",
+ "IStreamListener",
+ "IStreamSource",
+ "IAudioService",
+ "IDataSource",
+ "IDrmClient",
+ "IMediaCodecList",
+ "IMediaDrmService",
+ "IMediaExtractor",
+ "IMediaExtractorService",
+ "IMediaHTTPConnection",
+ "IMediaHTTPService",
+ "IMediaLogService",
+ "IMediaMetadataRetriever",
+ "IMediaMetricsService",
+ "IMediaPlayer",
+ "IMediaPlayerClient",
+ "IMediaPlayerService",
+ "IMediaRecorder",
+ "IMediaRecorderClient",
+ "IMediaResourceMonitor",
+ "IMediaSource",
+ "IRemoteDisplay",
+ "IRemoteDisplayClient",
+ "IResourceManagerClient",
+ "IResourceManagerService",
+ "IComplexTypeInterface",
+ "IPermissionController",
+ "IPingResponder",
+ "IProcessInfoService",
+ "ISchedulingPolicyService",
+ "IStringConstants",
+ "IObbActionListener",
+ "IStorageEventListener",
+ "IStorageManager",
+ "IStorageShutdownObserver",
+ "IPersistentVrStateCallbacks",
+ "IVrManager",
+ "IVrStateCallbacks",
+ "ISurfaceComposer",
+ "IMemory",
+ "IMemoryHeap",
+ "IProcfsInspector",
+ "IAppOpsCallback",
+ "IAppOpsService",
+ "IBatteryStats",
+ "IResultReceiver",
+ "IShellCallback",
+ "IDrmManagerService",
+ "IDrmServiceListener",
+ "IAAudioClient",
+ "IAAudioService",
+ "VtsFuzzer",
)
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
index 0baac2c7aacf..0a66cd510353 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
@@ -40,6 +40,8 @@ import org.jetbrains.uast.UElement
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.toUElement
+import java.util.EnumSet
+
/**
* Lint Detector that ensures that any method overriding a method annotated
* with @EnforcePermission is also annotated with the exact same annotation.
@@ -206,7 +208,7 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner {
severity = Severity.ERROR,
implementation = Implementation(
EnforcePermissionDetector::class.java,
- Scope.JAVA_FILE_SCOPE
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
)
)
@@ -219,7 +221,7 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner {
severity = Severity.ERROR,
implementation = Implementation(
EnforcePermissionDetector::class.java,
- Scope.JAVA_FILE_SCOPE
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
)
)
}
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
index df13af516514..cbbf91b49ded 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
@@ -34,6 +34,8 @@ import org.jetbrains.uast.UExpression
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.skipParenthesizedExprDown
+import java.util.EnumSet
+
class EnforcePermissionHelperDetector : Detector(), SourceCodeScanner {
override fun getApplicableUastTypes(): List<Class<out UElement?>> =
listOf(UMethod::class.java)
@@ -117,7 +119,7 @@ class EnforcePermissionHelperDetector : Detector(), SourceCodeScanner {
severity = Severity.ERROR,
implementation = Implementation(
EnforcePermissionHelperDetector::class.java,
- Scope.JAVA_FILE_SCOPE
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
)
)
@@ -130,7 +132,7 @@ class EnforcePermissionHelperDetector : Detector(), SourceCodeScanner {
severity = Severity.ERROR,
implementation = Implementation(
EnforcePermissionDetector::class.java,
- Scope.JAVA_FILE_SCOPE
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
)
)
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt
index c7be36efd991..22f749eee36b 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt
@@ -53,10 +53,9 @@ class SimpleManualPermissionEnforcementDetector : AidlImplementationDetector() {
lintFix
)
- // TODO(b/265014041): turn on errors once all code that would cause one is fixed
- // if (enforcePermissionFix.errorLevel) {
- // incident.overrideSeverity(Severity.ERROR)
- // }
+ if (enforcePermissionFix.errorLevel) {
+ incident.overrideSeverity(Severity.ERROR)
+ }
context.report(incident)
}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt
index 6b8e72cf9222..9170e752934f 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt
@@ -51,10 +51,10 @@ class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
.run()
.expect(
"""
- src/Foo.java:7: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+ src/Foo.java:7: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 0 errors, 1 warnings
+ 1 errors, 0 warnings
"""
)
.expectFixDiffs(
@@ -168,10 +168,10 @@ class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
.run()
.expect(
"""
- src/Foo.java:8: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+ src/Foo.java:8: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
mContext.enforceCallingOrSelfPermission(
^
- 0 errors, 1 warnings
+ 1 errors, 0 warnings
"""
)
.expectFixDiffs(
@@ -209,10 +209,10 @@ class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
.run()
.expect(
"""
- src/Foo.java:8: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+ src/Foo.java:8: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 0 errors, 1 warnings
+ 1 errors, 0 warnings
"""
)
.expectFixDiffs(
@@ -252,10 +252,10 @@ class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
.run()
.expect(
"""
- src/Foo.java:10: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+ src/Foo.java:10: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
mContext.enforceCallingOrSelfPermission(
^
- 0 errors, 1 warnings
+ 1 errors, 0 warnings
"""
)
.expectFixDiffs(
@@ -414,10 +414,10 @@ class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
.run()
.expect(
"""
- src/Foo.java:14: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+ src/Foo.java:14: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
helper();
~~~~~~~~~
- 0 errors, 1 warnings
+ 1 errors, 0 warnings
"""
)
.expectFixDiffs(
@@ -506,10 +506,10 @@ class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
.run()
.expect(
"""
- src/Foo.java:16: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+ src/Foo.java:16: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
mContext.enforceCallingOrSelfPermission("FOO", "foo");
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 0 errors, 1 warnings
+ 1 errors, 0 warnings
"""
)
.expectFixDiffs(
@@ -558,10 +558,10 @@ class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
.run()
.expect(
"""
- src/Foo.java:19: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+ src/Foo.java:19: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
helperHelper();
~~~~~~~~~~~~~~~
- 0 errors, 1 warnings
+ 1 errors, 0 warnings
"""
)
.expectFixDiffs(
@@ -599,10 +599,10 @@ class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
.run()
.expect(
"""
- src/Foo.java:7: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+ src/Foo.java:7: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
if (mContext.checkCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo")
^
- 0 errors, 1 warnings
+ 1 errors, 0 warnings
"""
)
.expectFixDiffs(
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index 039bb4e2788c..46745e995f64 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/Android.bp
@@ -11,7 +11,7 @@ java_library_host {
name: "protologtool-lib",
srcs: [
"src/com/android/protolog/tool/**/*.kt",
- ":protolog-common-src",
+ ":protolog-common-no-android-src",
],
static_libs: [
"javaparser",
diff --git a/tools/xmlpersistence/Android.bp b/tools/xmlpersistence/Android.bp
deleted file mode 100644
index 0b6dba626794..000000000000
--- a/tools/xmlpersistence/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_binary_host {
- name: "xmlpersistence_cli",
- manifest: "manifest.txt",
- srcs: [
- "src/**/*.kt",
- ],
- static_libs: [
- "javaparser-symbol-solver",
- "javapoet",
- ],
-}
diff --git a/tools/xmlpersistence/OWNERS b/tools/xmlpersistence/OWNERS
deleted file mode 100644
index 4f4d06a32676..000000000000
--- a/tools/xmlpersistence/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-zhanghai@google.com
diff --git a/tools/xmlpersistence/manifest.txt b/tools/xmlpersistence/manifest.txt
deleted file mode 100644
index 6d9771998efc..000000000000
--- a/tools/xmlpersistence/manifest.txt
+++ /dev/null
@@ -1 +0,0 @@
-Main-class: MainKt
diff --git a/tools/xmlpersistence/src/main/kotlin/Generator.kt b/tools/xmlpersistence/src/main/kotlin/Generator.kt
deleted file mode 100644
index 8e62388c860f..000000000000
--- a/tools/xmlpersistence/src/main/kotlin/Generator.kt
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.JavaFile
-import com.squareup.javapoet.MethodSpec
-import com.squareup.javapoet.NameAllocator
-import com.squareup.javapoet.ParameterSpec
-import com.squareup.javapoet.TypeSpec
-import java.io.File
-import java.io.FileInputStream
-import java.io.FileNotFoundException
-import java.io.FileOutputStream
-import java.io.IOException
-import java.nio.charset.StandardCharsets
-import java.time.Year
-import java.util.Objects
-import javax.lang.model.element.Modifier
-
-// JavaPoet only supports line comments, and can't add a newline after file level comments.
-val FILE_HEADER = """
- /*
- * Copyright (C) ${Year.now().value} 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.
- */
-
- // Generated by xmlpersistence. DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- // @formatter:off
-""".trimIndent() + "\n\n"
-
-private val atomicFileType = ClassName.get("android.util", "AtomicFile")
-
-fun generate(persistence: PersistenceInfo): JavaFile {
- val distinctClassFields = persistence.root.allClassFields.distinctBy { it.type }
- val type = TypeSpec.classBuilder(persistence.name)
- .addJavadoc(
- """
- Generated class implementing XML persistence for${'$'}W{@link $1T}.
- <p>
- This class provides atomicity for persistence via {@link $2T}, however it does not provide
- thread safety, so please bring your own synchronization mechanism.
- """.trimIndent(), persistence.root.type, atomicFileType
- )
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .addField(generateFileField())
- .addMethod(generateConstructor())
- .addMethod(generateReadMethod(persistence.root))
- .addMethod(generateParseMethod(persistence.root))
- .addMethods(distinctClassFields.map { generateParseClassMethod(it) })
- .addMethod(generateWriteMethod(persistence.root))
- .addMethod(generateSerializeMethod(persistence.root))
- .addMethods(distinctClassFields.map { generateSerializeClassMethod(it) })
- .addMethod(generateDeleteMethod())
- .build()
- return JavaFile.builder(persistence.root.type.packageName(), type)
- .skipJavaLangImports(true)
- .indent(" ")
- .build()
-}
-
-private val nonNullType = ClassName.get("android.annotation", "NonNull")
-
-private fun generateFileField(): FieldSpec =
- FieldSpec.builder(atomicFileType, "mFile", Modifier.PRIVATE, Modifier.FINAL)
- .addAnnotation(nonNullType)
- .build()
-
-private fun generateConstructor(): MethodSpec =
- MethodSpec.constructorBuilder()
- .addJavadoc(
- """
- Create an instance of this class.
-
- @param file the XML file for persistence
- """.trimIndent()
- )
- .addModifiers(Modifier.PUBLIC)
- .addParameter(
- ParameterSpec.builder(File::class.java, "file").addAnnotation(nonNullType).build()
- )
- .addStatement("mFile = new \$1T(file)", atomicFileType)
- .build()
-
-private val nullableType = ClassName.get("android.annotation", "Nullable")
-
-private val xmlPullParserType = ClassName.get("org.xmlpull.v1", "XmlPullParser")
-
-private val xmlType = ClassName.get("android.util", "Xml")
-
-private val xmlPullParserExceptionType = ClassName.get("org.xmlpull.v1", "XmlPullParserException")
-
-private fun generateReadMethod(rootField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder("read")
- .addJavadoc(
- """
- Read${'$'}W{@link $1T}${'$'}Wfrom${'$'}Wthe${'$'}WXML${'$'}Wfile.
-
- @return the persisted${'$'}W{@link $1T},${'$'}Wor${'$'}W{@code null}${'$'}Wif${'$'}Wthe${'$'}WXML${'$'}Wfile${'$'}Wdoesn't${'$'}Wexist
- @throws IllegalArgumentException if an error occurred while reading
- """.trimIndent(), rootField.type
- )
- .addAnnotation(nullableType)
- .addModifiers(Modifier.PUBLIC)
- .returns(rootField.type)
- .addControlFlow("try (\$1T inputStream = mFile.openRead())", FileInputStream::class.java) {
- addStatement("final \$1T parser = \$2T.newPullParser()", xmlPullParserType, xmlType)
- addStatement("parser.setInput(inputStream, null)")
- addStatement("return parse(parser)")
- nextControlFlow("catch (\$1T e)", FileNotFoundException::class.java)
- addStatement("return null")
- nextControlFlow(
- "catch (\$1T | \$2T e)", IOException::class.java, xmlPullParserExceptionType
- )
- addStatement("throw new IllegalArgumentException(e)")
- }
- .build()
-
-private val ClassFieldInfo.allClassFields: List<ClassFieldInfo>
- get() =
- mutableListOf<ClassFieldInfo>().apply {
- this += this@allClassFields
- for (field in fields) {
- when (field) {
- is ClassFieldInfo -> this += field.allClassFields
- is ListFieldInfo -> this += field.element.allClassFields
- else -> {}
- }
- }
- }
-
-private fun generateParseMethod(rootField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder("parse")
- .addAnnotation(nonNullType)
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
- .returns(rootField.type)
- .addParameter(
- ParameterSpec.builder(xmlPullParserType, "parser").addAnnotation(nonNullType).build()
- )
- .addExceptions(listOf(ClassName.get(IOException::class.java), xmlPullParserExceptionType))
- .apply {
- addStatement("int type")
- addStatement("int depth")
- addStatement("int innerDepth = parser.getDepth() + 1")
- addControlFlow(
- "while ((type = parser.next()) != \$1T.END_DOCUMENT\$W"
- + "&& ((depth = parser.getDepth()) >= innerDepth || type != \$1T.END_TAG))",
- xmlPullParserType
- ) {
- addControlFlow(
- "if (depth > innerDepth || type != \$1T.START_TAG)", xmlPullParserType
- ) {
- addStatement("continue")
- }
- addControlFlow(
- "if (\$1T.equals(parser.getName(),\$W\$2S))", Objects::class.java,
- rootField.tagName
- ) {
- addStatement("return \$1L(parser)", rootField.parseMethodName)
- }
- }
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Missing root tag <${rootField.tagName}>"
- )
- }
- .build()
-
-private fun generateParseClassMethod(classField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder(classField.parseMethodName)
- .addAnnotation(nonNullType)
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
- .returns(classField.type)
- .addParameter(
- ParameterSpec.builder(xmlPullParserType, "parser").addAnnotation(nonNullType).build()
- )
- .apply {
- val (attributeFields, tagFields) = classField.fields
- .partition { it is PrimitiveFieldInfo || it is StringFieldInfo }
- if (tagFields.isNotEmpty()) {
- addExceptions(
- listOf(ClassName.get(IOException::class.java), xmlPullParserExceptionType)
- )
- }
- val nameAllocator = NameAllocator().apply {
- newName("parser")
- newName("type")
- newName("depth")
- newName("innerDepth")
- }
- for (field in attributeFields) {
- val variableName = nameAllocator.newName(field.variableName, field)
- when (field) {
- is PrimitiveFieldInfo -> {
- val stringVariableName =
- nameAllocator.newName("${field.variableName}String")
- addStatement(
- "final String \$1L =\$Wparser.getAttributeValue(null,\$W\$2S)",
- stringVariableName, field.attributeName
- )
- if (field.isRequired) {
- addControlFlow("if (\$1L == null)", stringVariableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Missing attribute \"${field.attributeName}\""
- )
- }
- }
- val boxedType = field.type.box()
- val parseTypeMethodName = if (field.type.isPrimitive) {
- "parse${field.type.toString().capitalize()}"
- } else {
- "valueOf"
- }
- if (field.isRequired) {
- addStatement(
- "final \$1T \$2L =\$W\$3T.\$4L($5L)", field.type, variableName,
- boxedType, parseTypeMethodName, stringVariableName
- )
- } else {
- addStatement(
- "final \$1T \$2L =\$W$3L != null ?\$W\$4T.\$5L($3L)\$W: null",
- field.type, variableName, stringVariableName, boxedType,
- parseTypeMethodName
- )
- }
- }
- is StringFieldInfo ->
- addStatement(
- "final String \$1L =\$Wparser.getAttributeValue(null,\$W\$2S)",
- variableName, field.attributeName
- )
- else -> error(field)
- }
- }
- if (tagFields.isNotEmpty()) {
- for (field in tagFields) {
- val variableName = nameAllocator.newName(field.variableName, field)
- when (field) {
- is ClassFieldInfo ->
- addStatement("\$1T \$2L =\$Wnull", field.type, variableName)
- is ListFieldInfo ->
- addStatement(
- "final \$1T \$2L =\$Wnew \$3T<>()", field.type, variableName,
- ArrayList::class.java
- )
- else -> error(field)
- }
- }
- addStatement("int type")
- addStatement("int depth")
- addStatement("int innerDepth = parser.getDepth() + 1")
- addControlFlow(
- "while ((type = parser.next()) != \$1T.END_DOCUMENT\$W"
- + "&& ((depth = parser.getDepth()) >= innerDepth || type != \$1T.END_TAG))",
- xmlPullParserType
- ) {
- addControlFlow(
- "if (depth > innerDepth || type != \$1T.START_TAG)", xmlPullParserType
- ) {
- addStatement("continue")
- }
- addControlFlow("switch (parser.getName())") {
- for (field in tagFields) {
- addControlFlow("case \$1S:", field.tagName) {
- val variableName = nameAllocator.get(field)
- when (field) {
- is ClassFieldInfo -> {
- addControlFlow("if (\$1L != null)", variableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Duplicate tag \"${field.tagName}\""
- )
- }
- addStatement(
- "\$1L =\$W\$2L(parser)", variableName,
- field.parseMethodName
- )
- addStatement("break")
- }
- is ListFieldInfo -> {
- val elementNameAllocator = nameAllocator.clone()
- val elementVariableName = elementNameAllocator.newName(
- field.element.xmlName!!.toLowerCamelCase()
- )
- addStatement(
- "final \$1T \$2L =\$W\$3L(parser)", field.element.type,
- elementVariableName, field.element.parseMethodName
- )
- addStatement(
- "\$1L.add(\$2L)", variableName, elementVariableName
- )
- addStatement("break")
- }
- else -> error(field)
- }
- }
- }
- }
- }
- }
- for (field in tagFields.filter { it is ClassFieldInfo && it.isRequired }) {
- addControlFlow("if ($1L == null)", nameAllocator.get(field)) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)", "Missing tag <${field.tagName}>"
- )
- }
- }
- addStatement(
- classField.fields.joinToString(",\$W", "return new \$1T(", ")") {
- nameAllocator.get(it)
- }, classField.type
- )
- }
- .build()
-
-private val ClassFieldInfo.parseMethodName: String
- get() = "parse${type.simpleName().toUpperCamelCase()}"
-
-private val xmlSerializerType = ClassName.get("org.xmlpull.v1", "XmlSerializer")
-
-private fun generateWriteMethod(rootField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder("write")
- .apply {
- val nameAllocator = NameAllocator().apply {
- newName("outputStream")
- newName("serializer")
- }
- val parameterName = nameAllocator.newName(rootField.variableName)
- addJavadoc(
- """
- Write${'$'}W{@link $1T}${'$'}Wto${'$'}Wthe${'$'}WXML${'$'}Wfile.
-
- @param $2L the${'$'}W{@link ${'$'}1T}${'$'}Wto${'$'}Wpersist
- """.trimIndent(), rootField.type, parameterName
- )
- addAnnotation(nullableType)
- addModifiers(Modifier.PUBLIC)
- addParameter(
- ParameterSpec.builder(rootField.type, parameterName)
- .addAnnotation(nonNullType)
- .build()
- )
- addStatement("\$1T outputStream = null", FileOutputStream::class.java)
- addControlFlow("try") {
- addStatement("outputStream = mFile.startWrite()")
- addStatement(
- "final \$1T serializer =\$W\$2T.newSerializer()", xmlSerializerType, xmlType
- )
- addStatement(
- "serializer.setOutput(outputStream, \$1T.UTF_8.name())",
- StandardCharsets::class.java
- )
- addStatement(
- "serializer.setFeature(\$1S, true)",
- "http://xmlpull.org/v1/doc/features.html#indent-output"
- )
- addStatement("serializer.startDocument(null, true)")
- addStatement("serialize(serializer,\$W\$1L)", parameterName)
- addStatement("serializer.endDocument()")
- addStatement("mFile.finishWrite(outputStream)")
- nextControlFlow("catch (Exception e)")
- addStatement("e.printStackTrace()")
- addStatement("mFile.failWrite(outputStream)")
- }
- }
- .build()
-
-private fun generateSerializeMethod(rootField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder("serialize")
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
- .addParameter(
- ParameterSpec.builder(xmlSerializerType, "serializer")
- .addAnnotation(nonNullType)
- .build()
- )
- .apply {
- val nameAllocator = NameAllocator().apply { newName("serializer") }
- val parameterName = nameAllocator.newName(rootField.variableName)
- addParameter(
- ParameterSpec.builder(rootField.type, parameterName)
- .addAnnotation(nonNullType)
- .build()
- )
- addException(IOException::class.java)
- addStatement("serializer.startTag(null, \$1S)", rootField.tagName)
- addStatement("\$1L(serializer, \$2L)", rootField.serializeMethodName, parameterName)
- addStatement("serializer.endTag(null, \$1S)", rootField.tagName)
- }
- .build()
-
-private fun generateSerializeClassMethod(classField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder(classField.serializeMethodName)
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
- .addParameter(
- ParameterSpec.builder(xmlSerializerType, "serializer")
- .addAnnotation(nonNullType)
- .build()
- )
- .apply {
- val nameAllocator = NameAllocator().apply {
- newName("serializer")
- newName("i")
- }
- val parameterName = nameAllocator.newName(classField.serializeParameterName)
- addParameter(
- ParameterSpec.builder(classField.type, parameterName)
- .addAnnotation(nonNullType)
- .build()
- )
- addException(IOException::class.java)
- val (attributeFields, tagFields) = classField.fields
- .partition { it is PrimitiveFieldInfo || it is StringFieldInfo }
- for (field in attributeFields) {
- val variableName = "$parameterName.${field.name}"
- if (!field.isRequired) {
- beginControlFlow("if (\$1L != null)", variableName)
- }
- when (field) {
- is PrimitiveFieldInfo -> {
- if (field.isRequired && !field.type.isPrimitive) {
- addControlFlow("if (\$1L == null)", variableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Field \"${field.name}\" is null"
- )
- }
- }
- val stringVariableName =
- nameAllocator.newName("${field.variableName}String")
- addStatement(
- "final String \$1L =\$WString.valueOf(\$2L)", stringVariableName,
- variableName
- )
- addStatement(
- "serializer.attribute(null, \$1S, \$2L)", field.attributeName,
- stringVariableName
- )
- }
- is StringFieldInfo -> {
- if (field.isRequired) {
- addControlFlow("if (\$1L == null)", variableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Field \"${field.name}\" is null"
- )
- }
- }
- addStatement(
- "serializer.attribute(null, \$1S, \$2L)", field.attributeName,
- variableName
- )
- }
- else -> error(field)
- }
- if (!field.isRequired) {
- endControlFlow()
- }
- }
- for (field in tagFields) {
- val variableName = "$parameterName.${field.name}"
- if (field.isRequired) {
- addControlFlow("if (\$1L == null)", variableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Field \"${field.name}\" is null"
- )
- }
- }
- when (field) {
- is ClassFieldInfo -> {
- addStatement("serializer.startTag(null, \$1S)", field.tagName)
- addStatement(
- "\$1L(serializer, \$2L)", field.serializeMethodName, variableName
- )
- addStatement("serializer.endTag(null, \$1S)", field.tagName)
- }
- is ListFieldInfo -> {
- val sizeVariableName = nameAllocator.newName("${field.variableName}Size")
- addStatement(
- "final int \$1L =\$W\$2L.size()", sizeVariableName, variableName
- )
- addControlFlow("for (int i = 0;\$Wi < \$1L;\$Wi++)", sizeVariableName) {
- val elementNameAllocator = nameAllocator.clone()
- val elementVariableName = elementNameAllocator.newName(
- field.element.xmlName!!.toLowerCamelCase()
- )
- addStatement(
- "final \$1T \$2L =\$W\$3L.get(i)", field.element.type,
- elementVariableName, variableName
- )
- addControlFlow("if (\$1L == null)", elementVariableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S\$W+ i\$W+ \$2S)",
- "Field element \"${field.name}[", "]\" is null"
- )
- }
- addStatement("serializer.startTag(null, \$1S)", field.element.tagName)
- addStatement(
- "\$1L(serializer,\$W\$2L)", field.element.serializeMethodName,
- elementVariableName
- )
- addStatement("serializer.endTag(null, \$1S)", field.element.tagName)
- }
- }
- else -> error(field)
- }
- }
- }
- .build()
-
-private val ClassFieldInfo.serializeMethodName: String
- get() = "serialize${type.simpleName().toUpperCamelCase()}"
-
-private val ClassFieldInfo.serializeParameterName: String
- get() = type.simpleName().toLowerCamelCase()
-
-private val FieldInfo.variableName: String
- get() = name.toLowerCamelCase()
-
-private val FieldInfo.attributeName: String
- get() {
- check(this is PrimitiveFieldInfo || this is StringFieldInfo)
- return xmlNameOrName.toLowerCamelCase()
- }
-
-private val FieldInfo.tagName: String
- get() {
- check(this is ClassFieldInfo || this is ListFieldInfo)
- return xmlNameOrName.toLowerKebabCase()
- }
-
-private val FieldInfo.xmlNameOrName: String
- get() = xmlName ?: name
-
-private fun generateDeleteMethod(): MethodSpec =
- MethodSpec.methodBuilder("delete")
- .addJavadoc("Delete the XML file, if any.")
- .addModifiers(Modifier.PUBLIC)
- .addStatement("mFile.delete()")
- .build()
-
-private inline fun MethodSpec.Builder.addControlFlow(
- controlFlow: String,
- vararg args: Any,
- block: MethodSpec.Builder.() -> Unit
-): MethodSpec.Builder {
- beginControlFlow(controlFlow, *args)
- block()
- endControlFlow()
- return this
-}
diff --git a/tools/xmlpersistence/src/main/kotlin/Main.kt b/tools/xmlpersistence/src/main/kotlin/Main.kt
deleted file mode 100644
index e271f8cb9361..000000000000
--- a/tools/xmlpersistence/src/main/kotlin/Main.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-import java.io.File
-import java.nio.file.Files
-
-fun main(args: Array<String>) {
- val showUsage = args.isEmpty() || when (args.singleOrNull()) {
- "-h", "--help" -> true
- else -> false
- }
- if (showUsage) {
- usage()
- return
- }
-
- val files = args.flatMap {
- File(it).walk().filter { it.isFile && it.extension == "java" }.map { it.toPath() }
- }
- val persistences = parse(files)
- for (persistence in persistences) {
- val file = generate(persistence)
- Files.newBufferedWriter(persistence.path).use {
- it.write(FILE_HEADER)
- file.writeTo(it)
- }
- }
-}
-
-private fun usage() {
- println("Usage: xmlpersistence <FILES>")
-}
diff --git a/tools/xmlpersistence/src/main/kotlin/Parser.kt b/tools/xmlpersistence/src/main/kotlin/Parser.kt
deleted file mode 100644
index 3ea12a9aa389..000000000000
--- a/tools/xmlpersistence/src/main/kotlin/Parser.kt
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-import com.github.javaparser.JavaParser
-import com.github.javaparser.ParseProblemException
-import com.github.javaparser.ParseResult
-import com.github.javaparser.ParserConfiguration
-import com.github.javaparser.ast.Node
-import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
-import com.github.javaparser.ast.body.FieldDeclaration
-import com.github.javaparser.ast.body.TypeDeclaration
-import com.github.javaparser.ast.expr.AnnotationExpr
-import com.github.javaparser.ast.expr.Expression
-import com.github.javaparser.ast.expr.NormalAnnotationExpr
-import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr
-import com.github.javaparser.ast.expr.StringLiteralExpr
-import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration
-import com.github.javaparser.resolution.types.ResolvedPrimitiveType
-import com.github.javaparser.resolution.types.ResolvedReferenceType
-import com.github.javaparser.symbolsolver.JavaSymbolSolver
-import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration
-import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver
-import com.github.javaparser.symbolsolver.resolution.typesolvers.MemoryTypeSolver
-import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver
-import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.ParameterizedTypeName
-import com.squareup.javapoet.TypeName
-import java.nio.file.Path
-import java.util.Optional
-
-class PersistenceInfo(
- val name: String,
- val root: ClassFieldInfo,
- val path: Path
-)
-
-sealed class FieldInfo {
- abstract val name: String
- abstract val xmlName: String?
- abstract val type: TypeName
- abstract val isRequired: Boolean
-}
-
-class PrimitiveFieldInfo(
- override val name: String,
- override val xmlName: String?,
- override val type: TypeName,
- override val isRequired: Boolean
-) : FieldInfo()
-
-class StringFieldInfo(
- override val name: String,
- override val xmlName: String?,
- override val isRequired: Boolean
-) : FieldInfo() {
- override val type: TypeName = ClassName.get(String::class.java)
-}
-
-class ClassFieldInfo(
- override val name: String,
- override val xmlName: String?,
- override val type: ClassName,
- override val isRequired: Boolean,
- val fields: List<FieldInfo>
-) : FieldInfo()
-
-class ListFieldInfo(
- override val name: String,
- override val xmlName: String?,
- override val type: ParameterizedTypeName,
- val element: ClassFieldInfo
-) : FieldInfo() {
- override val isRequired: Boolean = true
-}
-
-fun parse(files: List<Path>): List<PersistenceInfo> {
- val typeSolver = CombinedTypeSolver().apply { add(ReflectionTypeSolver()) }
- val javaParser = JavaParser(ParserConfiguration()
- .setSymbolResolver(JavaSymbolSolver(typeSolver)))
- val compilationUnits = files.map { javaParser.parse(it).getOrThrow() }
- val memoryTypeSolver = MemoryTypeSolver().apply {
- for (compilationUnit in compilationUnits) {
- for (typeDeclaration in compilationUnit.getNodesByClass<TypeDeclaration<*>>()) {
- val name = typeDeclaration.fullyQualifiedName.getOrNull() ?: continue
- addDeclaration(name, typeDeclaration.resolve())
- }
- }
- }
- typeSolver.add(memoryTypeSolver)
- return mutableListOf<PersistenceInfo>().apply {
- for (compilationUnit in compilationUnits) {
- val classDeclarations = compilationUnit
- .getNodesByClass<ClassOrInterfaceDeclaration>()
- .filter { !it.isInterface && (!it.isNestedType || it.isStatic) }
- this += classDeclarations.mapNotNull { parsePersistenceInfo(it) }
- }
- }
-}
-
-private fun parsePersistenceInfo(classDeclaration: ClassOrInterfaceDeclaration): PersistenceInfo? {
- val annotation = classDeclaration.getAnnotationByName("XmlPersistence").getOrNull()
- ?: return null
- val rootClassName = classDeclaration.nameAsString
- val name = annotation.getMemberValue("value")?.stringLiteralValue
- ?: "${rootClassName}Persistence"
- val rootXmlName = classDeclaration.getAnnotationByName("XmlName").getOrNull()
- ?.getMemberValue("value")?.stringLiteralValue
- val root = parseClassFieldInfo(
- rootXmlName ?: rootClassName, rootXmlName, true, classDeclaration
- )
- val path = classDeclaration.findCompilationUnit().get().storage.get().path
- .resolveSibling("$name.java")
- return PersistenceInfo(name, root, path)
-}
-
-private fun parseClassFieldInfo(
- name: String,
- xmlName: String?,
- isRequired: Boolean,
- classDeclaration: ClassOrInterfaceDeclaration
-): ClassFieldInfo {
- val fields = classDeclaration.fields.filterNot { it.isStatic }.map { parseFieldInfo(it) }
- val type = classDeclaration.resolve().typeName
- return ClassFieldInfo(name, xmlName, type, isRequired, fields)
-}
-
-private fun parseFieldInfo(field: FieldDeclaration): FieldInfo {
- require(field.isPublic && field.isFinal)
- val variable = field.variables.single()
- val name = variable.nameAsString
- val annotations = field.annotations + variable.type.annotations
- val annotation = annotations.getByName("XmlName")
- val xmlName = annotation?.getMemberValue("value")?.stringLiteralValue
- val isRequired = annotations.getByName("NonNull") != null
- return when (val type = variable.type.resolve()) {
- is ResolvedPrimitiveType -> {
- val primitiveType = type.typeName
- PrimitiveFieldInfo(name, xmlName, primitiveType, true)
- }
- is ResolvedReferenceType -> {
- when (type.qualifiedName) {
- Boolean::class.javaObjectType.name, Byte::class.javaObjectType.name,
- Short::class.javaObjectType.name, Char::class.javaObjectType.name,
- Integer::class.javaObjectType.name, Long::class.javaObjectType.name,
- Float::class.javaObjectType.name, Double::class.javaObjectType.name ->
- PrimitiveFieldInfo(name, xmlName, type.typeName, isRequired)
- String::class.java.name -> StringFieldInfo(name, xmlName, isRequired)
- List::class.java.name -> {
- requireNotNull(xmlName)
- val elementType = type.typeParametersValues().single()
- require(elementType is ResolvedReferenceType)
- val listType = ParameterizedTypeName.get(
- ClassName.get(List::class.java), elementType.typeName
- )
- val element = parseClassFieldInfo(
- "(element)", xmlName, true, elementType.classDeclaration
- )
- ListFieldInfo(name, xmlName, listType, element)
- }
- else -> parseClassFieldInfo(name, xmlName, isRequired, type.classDeclaration)
- }
- }
- else -> error(type)
- }
-}
-
-private fun <T> ParseResult<T>.getOrThrow(): T =
- if (isSuccessful) {
- result.get()
- } else {
- throw ParseProblemException(problems)
- }
-
-private inline fun <reified T : Node> Node.getNodesByClass(): List<T> =
- getNodesByClass(T::class.java)
-
-private fun <T : Node> Node.getNodesByClass(klass: Class<T>): List<T> = mutableListOf<T>().apply {
- if (klass.isInstance(this@getNodesByClass)) {
- this += klass.cast(this@getNodesByClass)
- }
- for (childNode in childNodes) {
- this += childNode.getNodesByClass(klass)
- }
-}
-
-private fun <T> Optional<T>.getOrNull(): T? = orElse(null)
-
-private fun List<AnnotationExpr>.getByName(name: String): AnnotationExpr? =
- find { it.name.identifier == name }
-
-private fun AnnotationExpr.getMemberValue(name: String): Expression? =
- when (this) {
- is NormalAnnotationExpr -> pairs.find { it.nameAsString == name }?.value
- is SingleMemberAnnotationExpr -> if (name == "value") memberValue else null
- else -> null
- }
-
-private val Expression.stringLiteralValue: String
- get() {
- require(this is StringLiteralExpr)
- return value
- }
-
-private val ResolvedReferenceType.classDeclaration: ClassOrInterfaceDeclaration
- get() {
- val resolvedClassDeclaration = typeDeclaration
- require(resolvedClassDeclaration is JavaParserClassDeclaration)
- return resolvedClassDeclaration.wrappedNode
- }
-
-private val ResolvedPrimitiveType.typeName: TypeName
- get() =
- when (this) {
- ResolvedPrimitiveType.BOOLEAN -> TypeName.BOOLEAN
- ResolvedPrimitiveType.BYTE -> TypeName.BYTE
- ResolvedPrimitiveType.SHORT -> TypeName.SHORT
- ResolvedPrimitiveType.CHAR -> TypeName.CHAR
- ResolvedPrimitiveType.INT -> TypeName.INT
- ResolvedPrimitiveType.LONG -> TypeName.LONG
- ResolvedPrimitiveType.FLOAT -> TypeName.FLOAT
- ResolvedPrimitiveType.DOUBLE -> TypeName.DOUBLE
- }
-
-// This doesn't support type parameters.
-private val ResolvedReferenceType.typeName: TypeName
- get() = typeDeclaration.typeName
-
-private val ResolvedReferenceTypeDeclaration.typeName: ClassName
- get() {
- val packageName = packageName
- val classNames = className.split(".")
- val topLevelClassName = classNames.first()
- val nestedClassNames = classNames.drop(1)
- return ClassName.get(packageName, topLevelClassName, *nestedClassNames.toTypedArray())
- }
diff --git a/tools/xmlpersistence/src/main/kotlin/StringCaseExtensions.kt b/tools/xmlpersistence/src/main/kotlin/StringCaseExtensions.kt
deleted file mode 100644
index b4bdbba7170b..000000000000
--- a/tools/xmlpersistence/src/main/kotlin/StringCaseExtensions.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-import java.util.Locale
-
-private val camelHumpBoundary = Regex(
- "-"
- + "|_"
- + "|(?<=[0-9])(?=[^0-9])"
- + "|(?<=[A-Z])(?=[^A-Za-z]|[A-Z][a-z])"
- + "|(?<=[a-z])(?=[^a-z])"
-)
-
-private fun String.toCamelHumps(): List<String> = split(camelHumpBoundary)
-
-fun String.toUpperCamelCase(): String =
- toCamelHumps().joinToString("") { it.toLowerCase(Locale.ROOT).capitalize(Locale.ROOT) }
-
-fun String.toLowerCamelCase(): String = toUpperCamelCase().decapitalize(Locale.ROOT)
-
-fun String.toUpperKebabCase(): String =
- toCamelHumps().joinToString("-") { it.toUpperCase(Locale.ROOT) }
-
-fun String.toLowerKebabCase(): String =
- toCamelHumps().joinToString("-") { it.toLowerCase(Locale.ROOT) }
-
-fun String.toUpperSnakeCase(): String =
- toCamelHumps().joinToString("_") { it.toUpperCase(Locale.ROOT) }
-
-fun String.toLowerSnakeCase(): String =
- toCamelHumps().joinToString("_") { it.toLowerCase(Locale.ROOT) }