Merge "hiddenapi: Fix class hierarchy traversal"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index bd306b6..21eee7a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -38,6 +38,7 @@
GetMethodSignature \
HiddenApi \
HiddenApiSignatures \
+ HiddenApiStubs \
ImageLayoutA \
ImageLayoutB \
IMTA \
@@ -188,7 +189,7 @@
ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ManyMethods Statics VerifierDeps MainUncompressed EmptyUncompressed StringLiterals
ART_GTEST_dex2oat_image_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps
ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
-ART_GTEST_hiddenapi_test_DEX_DEPS := HiddenApi
+ART_GTEST_hiddenapi_test_DEX_DEPS := HiddenApi HiddenApiStubs
ART_GTEST_hidden_api_test_DEX_DEPS := HiddenApiSignatures
ART_GTEST_image_test_DEX_DEPS := ImageLayoutA ImageLayoutB DefaultMethods VerifySoftFailDuringClinit
ART_GTEST_imtable_test_DEX_DEPS := IMTA IMTB
diff --git a/test/HiddenApi/AbstractPackageClass.java b/test/HiddenApi/AbstractPackageClass.java
new file mode 100644
index 0000000..8f955ca
--- /dev/null
+++ b/test/HiddenApi/AbstractPackageClass.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+abstract class AbstractPackageClass {
+ public void publicMethod2() {}
+}
diff --git a/test/HiddenApi/PackageClass.java b/test/HiddenApi/PackageClass.java
new file mode 100644
index 0000000..eece100
--- /dev/null
+++ b/test/HiddenApi/PackageClass.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+class PackageClass extends AbstractPackageClass implements PublicInterface {
+ public void publicMethod1() {}
+}
diff --git a/test/HiddenApi/PublicInterface.java b/test/HiddenApi/PublicInterface.java
new file mode 100644
index 0000000..77a3709
--- /dev/null
+++ b/test/HiddenApi/PublicInterface.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+public interface PublicInterface {
+ void publicMethod1();
+ void publicMethod2();
+}
diff --git a/test/HiddenApiStubs/HiddenApi b/test/HiddenApiStubs/HiddenApi
new file mode 100644
index 0000000..6841ab5
--- /dev/null
+++ b/test/HiddenApiStubs/HiddenApi
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+public interface PublicInterface {
+ void publicMethod();
+}
diff --git a/test/HiddenApiStubs/PublicInterface.java b/test/HiddenApiStubs/PublicInterface.java
new file mode 100644
index 0000000..77a3709
--- /dev/null
+++ b/test/HiddenApiStubs/PublicInterface.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+public interface PublicInterface {
+ void publicMethod1();
+ void publicMethod2();
+}
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index f426d02..2692f68 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -124,6 +124,7 @@
}
inline bool IsPublic() const { return HasAccessFlags(kAccPublic); }
+ inline bool IsInterface() const { return HasAccessFlags(kAccInterface); }
inline bool Equals(const DexClass& other) const {
bool equals = strcmp(GetDescriptor(), other.GetDescriptor()) == 0;
@@ -344,13 +345,13 @@
// See comment on Hierarchy::ForEachResolvableMember.
template<typename Fn>
bool ForEachResolvableMember(const DexMember& other, Fn fn) {
- return ForEachResolvableMember_Impl(other, fn) != ResolutionResult::kNotFound;
+ std::vector<HierarchyClass*> visited;
+ return ForEachResolvableMember_Impl(other, fn, true, true, visited);
}
// Returns true if this class contains at least one member matching `other`.
bool HasMatchingMember(const DexMember& other) {
- return ForEachMatchingMember(
- other, [](const DexMember&) { return true; }) != ResolutionResult::kNotFound;
+ return ForEachMatchingMember(other, [](const DexMember&) { return true; });
}
// Recursively iterates over all subclasses of this class and invokes `fn`
@@ -366,62 +367,60 @@
}
private:
- // Result of resolution which takes into account whether the member was found
- // for the first time or not. This is just a performance optimization to prevent
- // re-visiting previously visited members.
- // Note that order matters. When accumulating results, we always pick the maximum.
- enum class ResolutionResult {
- kNotFound,
- kFoundOld,
- kFoundNew,
- };
-
- inline ResolutionResult Accumulate(ResolutionResult a, ResolutionResult b) {
- return static_cast<ResolutionResult>(
- std::max(static_cast<unsigned>(a), static_cast<unsigned>(b)));
- }
-
template<typename Fn>
- ResolutionResult ForEachResolvableMember_Impl(const DexMember& other, Fn fn) {
- // First try to find a member matching `other` in this class.
- ResolutionResult foundInClass = ForEachMatchingMember(other, fn);
-
- switch (foundInClass) {
- case ResolutionResult::kFoundOld:
- // A matching member was found and previously explored. All subclasses
- // must have been explored too.
- break;
-
- case ResolutionResult::kFoundNew:
- // A matching member was found and this was the first time it was visited.
- // If it is a virtual method, visit all methods overriding/implementing it too.
- if (other.IsVirtualMethod()) {
- for (HierarchyClass* subclass : extended_by_) {
- subclass->ForEachOverridingMember(other, fn);
- }
- }
- break;
-
- case ResolutionResult::kNotFound:
- // A matching member was not found in this class. Explore the superclasses
- // and implemented interfaces.
- for (HierarchyClass* superclass : extends_) {
- foundInClass = Accumulate(
- foundInClass, superclass->ForEachResolvableMember_Impl(other, fn));
- }
- break;
+ bool ForEachResolvableMember_Impl(const DexMember& other,
+ Fn fn,
+ bool allow_explore_up,
+ bool allow_explore_down,
+ std::vector<HierarchyClass*> visited) {
+ if (std::find(visited.begin(), visited.end(), this) == visited.end()) {
+ visited.push_back(this);
+ } else {
+ return false;
}
- return foundInClass;
+ // First try to find a member matching `other` in this class.
+ bool found = ForEachMatchingMember(other, fn);
+
+ // If not found, see if it is inherited from parents. Note that this will not
+ // revisit parents already in `visited`.
+ if (!found && allow_explore_up) {
+ for (HierarchyClass* superclass : extends_) {
+ found |= superclass->ForEachResolvableMember_Impl(
+ other,
+ fn,
+ /* allow_explore_up */ true,
+ /* allow_explore_down */ false,
+ visited);
+ }
+ }
+
+ // If this is a virtual method, continue exploring into subclasses so as to visit
+ // all overriding methods. Allow subclasses to explore their superclasses if this
+ // is an interface. This is needed to find implementations of this interface's
+ // methods inherited from superclasses (b/122551864).
+ if (allow_explore_down && other.IsVirtualMethod()) {
+ for (HierarchyClass* subclass : extended_by_) {
+ subclass->ForEachResolvableMember_Impl(
+ other,
+ fn,
+ /* allow_explore_up */ GetOneDexClass().IsInterface(),
+ /* allow_explore_down */ true,
+ visited);
+ }
+ }
+
+ return found;
}
template<typename Fn>
- ResolutionResult ForEachMatchingMember(const DexMember& other, Fn fn) {
- ResolutionResult found = ResolutionResult::kNotFound;
+ bool ForEachMatchingMember(const DexMember& other, Fn fn) {
+ bool found = false;
auto compare_member = [&](const DexMember& member) {
+ // TODO(dbrazdil): Check whether class of `other` can access `member`.
if (member == other) {
- found = Accumulate(found, fn(member) ? ResolutionResult::kFoundNew
- : ResolutionResult::kFoundOld);
+ found = true;
+ fn(member);
}
};
for (const DexClass& dex_class : dex_classes_) {
@@ -435,20 +434,6 @@
return found;
}
- template<typename Fn>
- void ForEachOverridingMember(const DexMember& other, Fn fn) {
- CHECK(other.IsVirtualMethod());
- ResolutionResult found = ForEachMatchingMember(other, fn);
- if (found == ResolutionResult::kFoundOld) {
- // No need to explore further.
- return;
- } else {
- for (HierarchyClass* subclass : extended_by_) {
- subclass->ForEachOverridingMember(other, fn);
- }
- }
- }
-
// DexClass entries of this class found across all the provided dex files.
std::vector<DexClass> dex_classes_;
@@ -1070,12 +1055,7 @@
std::string entry = boot_member.GetApiEntry();
auto it = boot_members.find(entry);
CHECK(it != boot_members.end());
- if (it->second.Contains(stub_api_list)) {
- return false; // has been marked before
- } else {
- it->second |= stub_api_list;
- return true; // marked for the first time
- }
+ it->second |= stub_api_list;
});
if (!resolved) {
unresolved.insert(stub_member.GetApiEntry());
diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc
index 7ef5b3d..74feb8a 100644
--- a/tools/hiddenapi/hiddenapi_test.cc
+++ b/tools/hiddenapi/hiddenapi_test.cc
@@ -16,6 +16,8 @@
#include <fstream>
+#include "android-base/strings.h"
+
#include "base/unix_file/fd_file.h"
#include "base/zip_archive.h"
#include "common_runtime_test.h"
@@ -41,9 +43,9 @@
return file_path;
}
- std::unique_ptr<const DexFile> RunHiddenApi(const ScratchFile& flags_csv,
- const std::vector<std::string>& extra_args,
- ScratchFile* out_dex) {
+ std::unique_ptr<const DexFile> RunHiddenapiEncode(const ScratchFile& flags_csv,
+ const std::vector<std::string>& extra_args,
+ const ScratchFile& out_dex) {
std::string error;
ScratchFile in_dex;
std::unique_ptr<ZipArchive> jar(
@@ -68,18 +70,42 @@
argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
argv_str.push_back("encode");
argv_str.push_back("--input-dex=" + in_dex.GetFilename());
- argv_str.push_back("--output-dex=" + out_dex->GetFilename());
+ argv_str.push_back("--output-dex=" + out_dex.GetFilename());
argv_str.push_back("--api-flags=" + flags_csv.GetFilename());
argv_str.push_back("--no-force-assign-all");
int return_code = ExecAndReturnCode(argv_str, &error);
if (return_code == 0) {
- return OpenDex(*out_dex);
+ return OpenDex(out_dex);
} else {
LOG(ERROR) << "HiddenApi binary exited with unexpected return code " << return_code;
return nullptr;
}
}
+ bool RunHiddenapiList(const ScratchFile& out_flags_csv) {
+ std::string error;
+ std::string boot_jar = GetTestDexFileName("HiddenApi");
+ std::string stub_jar = GetTestDexFileName("HiddenApiStubs");
+ std::string boot_cp = android::base::Join(GetLibCoreDexFileNames(), ":");
+
+ std::vector<std::string> argv_str;
+ argv_str.push_back(GetHiddenApiCmd());
+ argv_str.push_back("list");
+ for (const std::string& core_jar : GetLibCoreDexFileNames()) {
+ argv_str.push_back("--boot-dex=" + core_jar);
+ }
+ argv_str.push_back("--boot-dex=" + boot_jar);
+ argv_str.push_back("--public-stub-classpath=" + boot_cp + ":" + stub_jar);
+ argv_str.push_back("--out-api-flags=" + out_flags_csv.GetFilename());
+ int return_code = ExecAndReturnCode(argv_str, &error);
+ if (return_code == 0) {
+ return true;
+ } else {
+ LOG(ERROR) << "HiddenApi binary exited with unexpected return code " << return_code;
+ return false;
+ }
+ }
+
std::unique_ptr<const DexFile> OpenDex(const ScratchFile& file) {
ArtDexFileLoader dex_loader;
std::string error_msg;
@@ -113,6 +139,31 @@
return ofs;
}
+ std::map<std::string, std::string> ReadFlagsCsvFile(const ScratchFile& file) {
+ std::ifstream ifs(file.GetFilename());
+ std::map<std::string, std::string> flags;
+
+ for (std::string line; std::getline(ifs, line);) {
+ std::size_t comma = line.find(",");
+ if (comma == std::string::npos) {
+ flags.emplace(line, "");
+ } else {
+ flags.emplace(line.substr(0, comma), line.substr(comma + 1));
+ }
+ }
+
+ return flags;
+ }
+
+ std::string SafeMapGet(const std::string& key, const std::map<std::string, std::string>& map) {
+ auto it = map.find(key);
+ if (it == map.end()) {
+ LOG(FATAL) << "Key not found: " << key;
+ UNREACHABLE();
+ }
+ return it->second;
+ }
+
const dex::ClassDef& FindClass(const char* desc, const DexFile& dex_file) {
const dex::TypeId* type_id = dex_file.FindTypeId(desc);
CHECK(type_id != nullptr) << "Could not find class " << desc;
@@ -220,7 +271,7 @@
<< "LMain;->ifield:LBadType1;,greylist" << std::endl
<< "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl
<< "LMain;->ifield:LBadType3;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetIFieldHiddenFlags(*dex_file));
}
@@ -231,7 +282,7 @@
<< "LMain;->ifield:I,greylist" << std::endl
<< "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl
<< "LMain;->ifield:LBadType3;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetIFieldHiddenFlags(*dex_file));
}
@@ -242,7 +293,7 @@
<< "LMain;->ifield:LBadType1;,greylist" << std::endl
<< "LMain;->ifield:I,greylist-max-o" << std::endl
<< "LMain;->ifield:LBadType3;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetIFieldHiddenFlags(*dex_file));
}
@@ -253,7 +304,7 @@
<< "LMain;->ifield:LBadType1;,greylist" << std::endl
<< "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl
<< "LMain;->ifield:I,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetIFieldHiddenFlags(*dex_file));
}
@@ -263,7 +314,7 @@
OpenStream(flags_csv)
<< "LMain;->ifield:LBadType1;,greylist" << std::endl
<< "LMain;->ifield:I,blacklist,greylist-max-o" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -272,7 +323,7 @@
OpenStream(flags_csv)
<< "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl
<< "LMain;->ifield:I,blacklist,greylist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -281,7 +332,7 @@
OpenStream(flags_csv)
<< "LMain;->ifield:I,greylist,greylist-max-o" << std::endl
<< "LMain;->ifield:LBadType3;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -291,7 +342,7 @@
<< "LMain;->sfield:LBadType1;,greylist" << std::endl
<< "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl
<< "LMain;->sfield:LBadType3;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSFieldHiddenFlags(*dex_file));
}
@@ -302,7 +353,7 @@
<< "LMain;->sfield:Ljava/lang/Object;,greylist" << std::endl
<< "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl
<< "LMain;->sfield:LBadType3;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSFieldHiddenFlags(*dex_file));
}
@@ -313,7 +364,7 @@
<< "LMain;->sfield:LBadType1;,greylist" << std::endl
<< "LMain;->sfield:Ljava/lang/Object;,greylist-max-o" << std::endl
<< "LMain;->sfield:LBadType3;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSFieldHiddenFlags(*dex_file));
}
@@ -324,7 +375,7 @@
<< "LMain;->sfield:LBadType1;,greylist" << std::endl
<< "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl
<< "LMain;->sfield:Ljava/lang/Object;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSFieldHiddenFlags(*dex_file));
}
@@ -334,7 +385,7 @@
OpenStream(flags_csv)
<< "LMain;->sfield:LBadType1;,greylist" << std::endl
<< "LMain;->sfield:Ljava/lang/Object;,blacklist,greylist-max-o" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -343,7 +394,7 @@
OpenStream(flags_csv)
<< "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl
<< "LMain;->sfield:Ljava/lang/Object;,blacklist,greylist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -352,7 +403,7 @@
OpenStream(flags_csv)
<< "LMain;->sfield:Ljava/lang/Object;,greylist,greylist-max-o" << std::endl
<< "LMain;->sfield:LBadType3;,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -362,7 +413,7 @@
<< "LMain;->imethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->imethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetIMethodHiddenFlags(*dex_file));
}
@@ -373,7 +424,7 @@
<< "LMain;->imethod(J)V,greylist" << std::endl
<< "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->imethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetIMethodHiddenFlags(*dex_file));
}
@@ -384,7 +435,7 @@
<< "LMain;->imethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->imethod(J)V,greylist-max-o" << std::endl
<< "LMain;->imethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetIMethodHiddenFlags(*dex_file));
}
@@ -395,7 +446,7 @@
<< "LMain;->imethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->imethod(J)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetIMethodHiddenFlags(*dex_file));
}
@@ -405,7 +456,7 @@
OpenStream(flags_csv)
<< "LMain;->imethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->imethod(J)V,blacklist,greylist-max-o" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -414,7 +465,7 @@
OpenStream(flags_csv)
<< "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->imethod(J)V,blacklist,greylist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -423,7 +474,7 @@
OpenStream(flags_csv)
<< "LMain;->imethod(J)V,greylist,greylist-max-o" << std::endl
<< "LMain;->imethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -433,7 +484,7 @@
<< "LMain;->smethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->smethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSMethodHiddenFlags(*dex_file));
}
@@ -444,7 +495,7 @@
<< "LMain;->smethod(Ljava/lang/Object;)V,greylist" << std::endl
<< "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->smethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSMethodHiddenFlags(*dex_file));
}
@@ -455,7 +506,7 @@
<< "LMain;->smethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->smethod(Ljava/lang/Object;)V,greylist-max-o" << std::endl
<< "LMain;->smethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSMethodHiddenFlags(*dex_file));
}
@@ -466,7 +517,7 @@
<< "LMain;->smethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->smethod(Ljava/lang/Object;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSMethodHiddenFlags(*dex_file));
}
@@ -476,7 +527,7 @@
OpenStream(flags_csv)
<< "LMain;->smethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->smethod(Ljava/lang/Object;)V,blacklist,greylist-max-o" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -485,7 +536,7 @@
OpenStream(flags_csv)
<< "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->smethod(Ljava/lang/Object;)V,blacklist,greylist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -494,7 +545,7 @@
OpenStream(flags_csv)
<< "LMain;->smethod(Ljava/lang/Object;)V,greylist,greylist-max-o" << std::endl
<< "LMain;->smethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -504,7 +555,7 @@
<< "LMain;->inmethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetINMethodHiddenFlags(*dex_file));
}
@@ -515,7 +566,7 @@
<< "LMain;->inmethod(C)V,greylist" << std::endl
<< "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetINMethodHiddenFlags(*dex_file));
}
@@ -526,7 +577,7 @@
<< "LMain;->inmethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->inmethod(C)V,greylist-max-o" << std::endl
<< "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetINMethodHiddenFlags(*dex_file));
}
@@ -537,7 +588,7 @@
<< "LMain;->inmethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->inmethod(C)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetINMethodHiddenFlags(*dex_file));
}
@@ -547,7 +598,7 @@
OpenStream(flags_csv)
<< "LMain;->inmethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->inmethod(C)V,blacklist,greylist-max-o" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -556,7 +607,7 @@
OpenStream(flags_csv)
<< "LMain;->inmethod(C)V,blacklist,greylist" << std::endl
<< "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -565,7 +616,7 @@
OpenStream(flags_csv)
<< "LMain;->inmethod(C)V,greylist,greylist-max-o" << std::endl
<< "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -575,7 +626,7 @@
<< "LMain;->snmethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSNMethodHiddenFlags(*dex_file));
}
@@ -586,7 +637,7 @@
<< "LMain;->snmethod(Ljava/lang/Integer;)V,greylist" << std::endl
<< "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSNMethodHiddenFlags(*dex_file));
}
@@ -597,7 +648,7 @@
<< "LMain;->snmethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->snmethod(Ljava/lang/Integer;)V,greylist-max-o" << std::endl
<< "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSNMethodHiddenFlags(*dex_file));
}
@@ -608,7 +659,7 @@
<< "LMain;->snmethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl
<< "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSNMethodHiddenFlags(*dex_file));
}
@@ -618,7 +669,7 @@
OpenStream(flags_csv)
<< "LMain;->snmethod(LBadType1;)V,greylist" << std::endl
<< "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist,greylist-max-o" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -627,7 +678,7 @@
OpenStream(flags_csv)
<< "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist,greylist" << std::endl
<< "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
@@ -636,8 +687,35 @@
OpenStream(flags_csv)
<< "LMain;->snmethod(Ljava/lang/Integer;)V,greylist,greylist-max-o" << std::endl
<< "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl;
- auto dex_file = RunHiddenApi(flags_csv, {}, &dex);
+ auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_EQ(dex_file.get(), nullptr);
}
+// The following tests use this class hierarchy:
+//
+// AbstractPackageClass PublicInterface
+// | |
+// | ┌----------------┘
+// | |
+// PackageClass
+//
+// Only PublicInterface is in stubs.
+
+// Test a method declared in PublicInterface and defined in PackageClass.
+TEST_F(HiddenApiTest, InterfaceMethodImplemented) {
+ ScratchFile flags_csv;
+ ASSERT_TRUE(RunHiddenapiList(flags_csv));
+ auto flags = ReadFlagsCsvFile(flags_csv);
+ ASSERT_EQ(SafeMapGet("LPackageClass;->publicMethod1()V", flags), "whitelist");
+}
+
+// Test a method declared in PublicInterface, defined in AbstractPackageClass and
+// inherited by PackageClass.
+TEST_F(HiddenApiTest, InterfaceMethodImplementedInParent) {
+ ScratchFile flags_csv;
+ ASSERT_TRUE(RunHiddenapiList(flags_csv));
+ auto flags = ReadFlagsCsvFile(flags_csv);
+ ASSERT_EQ(SafeMapGet("LAbstractPackageClass;->publicMethod2()V", flags), "whitelist");
+}
+
} // namespace art