/* * Copyright (C) 2018 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. */ #include "hidden_api.h" #include #include #include "android-base/stringprintf.h" #include "base/file_utils.h" #include "base/sdk_version.h" #include "base/stl_util.h" #include "common_runtime_test.h" #include "jni/jni_internal.h" #include "proxy_test.h" #include "well_known_classes.h" namespace art { using android::base::StringPrintf; using hiddenapi::detail::MemberSignature; using hiddenapi::detail::ShouldDenyAccessToMemberImpl; // Should be the same as dalvik.system.VMRuntime.HIDE_MAXTARGETSDK_P_HIDDEN_APIS, // dalvik.system.VMRuntime.HIDE_MAXTARGETSDK_Q_HIDDEN_APIS, and // dalvik.system.VMRuntime.EXEMPT_TEST_API_ACCESS_VERIFICATION. static constexpr uint64_t kHideMaxtargetsdkPHiddenApis = 149997251; static constexpr uint64_t kHideMaxtargetsdkQHiddenApis = 149994052; static constexpr uint64_t kAllowTestApiAccess = 166236554; static bool Copy(const std::string& src, const std::string& dst, /*out*/ std::string* error_msg) { std::ifstream src_stream(src, std::ios::binary); std::ofstream dst_stream(dst, std::ios::binary); dst_stream << src_stream.rdbuf(); src_stream.close(); dst_stream.close(); if (src_stream.good() && dst_stream.good()) { return true; } else { *error_msg = "Copy " + src + " => " + dst + " (src_good=" + (src_stream.good() ? "true" : "false") + ", dst_good=" + (dst_stream.good() ? "true" : "false") + ")"; return false; } } static bool LoadDexFiles(const std::string& path, ScopedObjectAccess& soa, /* out */ std::vector>* dex_files, /* out */ ObjPtr* class_loader, /* out */ std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { if (!ArtDexFileLoader().Open(path.c_str(), path, /* verify= */ true, /* verify_checksum= */ true, error_msg, dex_files)) { return false; } ClassLinker* const linker = Runtime::Current()->GetClassLinker(); StackHandleScope<2> hs(soa.Self()); Handle h_class = hs.NewHandle(soa.Decode( WellKnownClasses::dalvik_system_PathClassLoader)); Handle h_loader = hs.NewHandle(linker->CreateWellKnownClassLoader( soa.Self(), MakeNonOwningPointerVector(*dex_files), h_class, /* parent_loader= */ ScopedNullHandle(), /* shared_libraries= */ ScopedNullHandle>())); for (const auto& dex_file : *dex_files) { linker->RegisterDexFile(*dex_file.get(), h_loader.Get()); } *class_loader = h_loader.Get(); return true; } static bool Remove(const std::string& path, /*out*/ std::string* error_msg) { if (TEMP_FAILURE_RETRY(remove(path.c_str())) == 0) { return true; } *error_msg = StringPrintf("Unable to remove(\"%s\"): %s", path.c_str(), strerror(errno)); return false; } static bool CheckAllDexFilesInDomain(ObjPtr loader, const std::vector>& dex_files, hiddenapi::Domain expected_domain, /* out */ std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { for (const auto& dex_file : dex_files) { hiddenapi::AccessContext context(loader, dex_file.get()); if (context.GetDomain() != expected_domain) { std::stringstream ss; ss << dex_file->GetLocation() << ": access context domain does not match " << "(expected=" << static_cast(expected_domain) << ", actual=" << static_cast(context.GetDomain()) << ")"; *error_msg = ss.str(); return false; } if (dex_file->GetHiddenapiDomain() != expected_domain) { std::stringstream ss; ss << dex_file->GetLocation() << ": dex file domain does not match " << "(expected=" << static_cast(expected_domain) << ", actual=" << static_cast(dex_file->GetHiddenapiDomain()) << ")"; *error_msg = ss.str(); return false; } } return true; } class HiddenApiTest : public CommonRuntimeTest { protected: void SetUp() override { // Do the normal setup. CommonRuntimeTest::SetUp(); self_ = Thread::Current(); self_->TransitionFromSuspendedToRunnable(); jclass_loader_ = LoadDex("HiddenApiSignatures"); bool started = runtime_->Start(); CHECK(started); class1_field1_ = GetArtField("mypackage/packagea/Class1", "field1", "I"); class1_field12_ = GetArtField("mypackage/packagea/Class1", "field12", "I"); class1_init_ = GetArtMethod("mypackage/packagea/Class1", "", "()V"); class1_method1_ = GetArtMethod("mypackage/packagea/Class1", "method1", "()V"); class1_method1_i_ = GetArtMethod("mypackage/packagea/Class1", "method1", "(I)V"); class1_method12_ = GetArtMethod("mypackage/packagea/Class1", "method12", "()V"); class12_field1_ = GetArtField("mypackage/packagea/Class12", "field1", "I"); class12_method1_ = GetArtMethod("mypackage/packagea/Class12", "method1", "()V"); class2_field1_ = GetArtField("mypackage/packagea/Class2", "field1", "I"); class2_method1_ = GetArtMethod("mypackage/packagea/Class2", "method1", "()V"); class2_method1_i_ = GetArtMethod("mypackage/packagea/Class2", "method1", "(I)V"); class3_field1_ = GetArtField("mypackage/packageb/Class3", "field1", "I"); class3_method1_ = GetArtMethod("mypackage/packageb/Class3", "method1", "()V"); class3_method1_i_ = GetArtMethod("mypackage/packageb/Class3", "method1", "(I)V"); } ArtMethod* GetArtMethod(const char* class_name, const char* name, const char* signature) { JNIEnv* env = Thread::Current()->GetJniEnv(); jclass klass = env->FindClass(class_name); jmethodID method_id = env->GetMethodID(klass, name, signature); ArtMethod* art_method = jni::DecodeArtMethod(method_id); return art_method; } ArtField* GetArtField(const char* class_name, const char* name, const char* signature) { JNIEnv* env = Thread::Current()->GetJniEnv(); jclass klass = env->FindClass(class_name); jfieldID field_id = env->GetFieldID(klass, name, signature); ArtField* art_field = jni::DecodeArtField(field_id); return art_field; } void SetChangeIdState(uint64_t change, bool enabled) { CompatFramework& compat_framework = runtime_->GetCompatFramework(); std::set disabled_changes = compat_framework.GetDisabledCompatChanges(); if (enabled) { disabled_changes.erase(change); } else { disabled_changes.insert(change); } compat_framework.SetDisabledCompatChanges(disabled_changes); } bool ShouldDenyAccess(hiddenapi::ApiList list) REQUIRES_SHARED(Locks::mutator_lock_) { // Choose parameters such that there are no side effects (AccessMethod::kNone) // and that the member is not on the exemptions list (here we choose one which // is not even in boot class path). return ShouldDenyAccessToMemberImpl(/* member= */ class1_field1_, list, /* access_method= */ hiddenapi::AccessMethod::kNone); } void TestLocation(const std::string& location, hiddenapi::Domain expected_domain) { ScopedObjectAccess soa(Thread::Current()); std::vector> dex_files; std::string error_msg; ObjPtr class_loader; ASSERT_TRUE(Copy(GetTestDexFileName("Main"), location, &error_msg)) << error_msg; ASSERT_TRUE(LoadDexFiles(location, soa, &dex_files, &class_loader, &error_msg)) << error_msg; ASSERT_GE(dex_files.size(), 1u); ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, expected_domain, &error_msg)) << error_msg; dex_files.clear(); ASSERT_TRUE(Remove(location, &error_msg)) << error_msg; } protected: Thread* self_; jobject jclass_loader_; ArtField* class1_field1_; ArtField* class1_field12_; ArtMethod* class1_init_; ArtMethod* class1_method1_; ArtMethod* class1_method1_i_; ArtMethod* class1_method12_; ArtField* class12_field1_; ArtMethod* class12_method1_; ArtField* class2_field1_; ArtMethod* class2_method1_; ArtMethod* class2_method1_i_; ArtField* class3_field1_; ArtMethod* class3_method1_; ArtMethod* class3_method1_i_; }; TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) { ScopedObjectAccess soa(self_); runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kJustWarn); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Sdk()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetR()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetQ()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetP()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetO()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blocked()), false); runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); runtime_->SetTargetSdkVersion( static_cast(hiddenapi::ApiList::MaxTargetO().GetMaxAllowedSdkVersion())); SetChangeIdState(kHideMaxtargetsdkPHiddenApis, false); SetChangeIdState(kHideMaxtargetsdkQHiddenApis, false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Sdk()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetR()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetQ()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetP()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetO()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blocked()), true); runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); runtime_->SetTargetSdkVersion( static_cast(hiddenapi::ApiList::MaxTargetO().GetMaxAllowedSdkVersion()) + 1); SetChangeIdState(kHideMaxtargetsdkPHiddenApis, false); SetChangeIdState(kHideMaxtargetsdkQHiddenApis, false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Sdk()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetR()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetQ()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetP()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetO()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blocked()), true); SetChangeIdState(kHideMaxtargetsdkQHiddenApis, true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Sdk()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetQ()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetP()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetO()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blocked()), true); runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); runtime_->SetTargetSdkVersion( static_cast(hiddenapi::ApiList::MaxTargetP().GetMaxAllowedSdkVersion()) + 1); SetChangeIdState(kHideMaxtargetsdkPHiddenApis, true); SetChangeIdState(kHideMaxtargetsdkQHiddenApis, false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Sdk()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetR()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetQ()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetP()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetO()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blocked()), true); runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); runtime_->SetTargetSdkVersion( static_cast(hiddenapi::ApiList::MaxTargetQ().GetMaxAllowedSdkVersion()) + 1); SetChangeIdState(kHideMaxtargetsdkPHiddenApis, true); SetChangeIdState(kHideMaxtargetsdkQHiddenApis, true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Sdk()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetR()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetQ()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetP()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetO()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blocked()), true); runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); runtime_->SetTargetSdkVersion( static_cast(hiddenapi::ApiList::MaxTargetR().GetMaxAllowedSdkVersion()) + 1); SetChangeIdState(kHideMaxtargetsdkPHiddenApis, true); SetChangeIdState(kHideMaxtargetsdkQHiddenApis, true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Sdk()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetR()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetQ()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetP()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::MaxTargetO()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blocked()), true); } TEST_F(HiddenApiTest, CheckTestApiEnforcement) { ScopedObjectAccess soa(self_); runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); runtime_->SetTargetSdkVersion( static_cast(hiddenapi::ApiList::MaxTargetR().GetMaxAllowedSdkVersion()) + 1); // Default case where all TestApis are treated like non-TestApi. runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); SetChangeIdState(kAllowTestApiAccess, false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Sdk()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetR()), true); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetQ()), true); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetP()), true); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetO()), true); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blocked()), true); // A case where we want to allow access to TestApis. runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled); SetChangeIdState(kAllowTestApiAccess, false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Sdk()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetR()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetQ()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetP()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetO()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blocked()), false); // A second case where we want to allow access to TestApis. runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); SetChangeIdState(kAllowTestApiAccess, true); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Sdk()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Unsupported()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetR()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetQ()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetP()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetO()), false); ASSERT_EQ( ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blocked()), false); } TEST_F(HiddenApiTest, CheckMembersRead) { ASSERT_NE(nullptr, class1_field1_); ASSERT_NE(nullptr, class1_field12_); ASSERT_NE(nullptr, class1_init_); ASSERT_NE(nullptr, class1_method1_); ASSERT_NE(nullptr, class1_method1_i_); ASSERT_NE(nullptr, class1_method12_); ASSERT_NE(nullptr, class12_field1_); ASSERT_NE(nullptr, class12_method1_); ASSERT_NE(nullptr, class2_field1_); ASSERT_NE(nullptr, class2_method1_); ASSERT_NE(nullptr, class2_method1_i_); ASSERT_NE(nullptr, class3_field1_); ASSERT_NE(nullptr, class3_method1_); ASSERT_NE(nullptr, class3_method1_i_); } TEST_F(HiddenApiTest, CheckEverythingMatchesL) { ScopedObjectAccess soa(self_); std::string prefix("L"); ASSERT_TRUE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class12_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class12_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method12_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class2_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class2_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class2_method1_i_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class3_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class3_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class3_method1_i_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckPackageMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/"); ASSERT_TRUE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method12_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class12_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class12_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class2_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class2_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class2_method1_i_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class3_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class3_method1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class3_method1_i_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckClassMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1"); ASSERT_TRUE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method12_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class12_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class12_method1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class2_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class2_method1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class2_method1_i_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckClassExactMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;"); ASSERT_TRUE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class12_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class12_method1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class2_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class2_method1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class2_method1_i_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckMethodMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->method1"); ASSERT_FALSE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method12_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class12_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class12_method1_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckMethodExactMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->method1("); ASSERT_FALSE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method12_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckMethodSignatureMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->method1(I)"); ASSERT_FALSE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method12_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckMethodSignatureAndReturnMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->method1()V"); ASSERT_FALSE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method12_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckFieldMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->field1"); ASSERT_TRUE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_TRUE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method1_i_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method12_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckFieldExactMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->field1:"); ASSERT_TRUE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckFieldTypeMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->field1:I"); ASSERT_TRUE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_field12_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckConstructorMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->"); ASSERT_TRUE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckConstructorExactMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->()V"); ASSERT_TRUE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); ASSERT_FALSE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckMethodSignatureTrailingCharsNoMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->method1()Vfoo"); ASSERT_FALSE(MemberSignature(class1_method1_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckConstructorTrailingCharsNoMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->()Vfoo"); ASSERT_FALSE(MemberSignature(class1_init_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckFieldTrailingCharsNoMatch) { ScopedObjectAccess soa(self_); std::string prefix("Lmypackage/packagea/Class1;->field1:Ifoo"); ASSERT_FALSE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix)); } TEST_F(HiddenApiTest, CheckMemberSignatureForProxyClass) { ScopedObjectAccess soa(self_); StackHandleScope<4> hs(soa.Self()); Handle class_loader( hs.NewHandle(soa.Decode(jclass_loader_))); // Find interface we will create a proxy for. Handle h_iface(hs.NewHandle( class_linker_->FindClass(soa.Self(), "Lmypackage/packagea/Interface;", class_loader))); ASSERT_TRUE(h_iface != nullptr); // Create the proxy class. std::vector> interfaces; interfaces.push_back(h_iface); Handle proxyClass = hs.NewHandle(proxy_test::GenerateProxyClass( soa, jclass_loader_, runtime_->GetClassLinker(), "$Proxy1234", interfaces)); ASSERT_TRUE(proxyClass != nullptr); ASSERT_TRUE(proxyClass->IsProxyClass()); ASSERT_TRUE(proxyClass->IsInitialized()); // Find the "method" virtual method. ArtMethod* method = nullptr; for (auto& m : proxyClass->GetDeclaredVirtualMethods(kRuntimePointerSize)) { if (strcmp("method", m.GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetName()) == 0) { method = &m; break; } } ASSERT_TRUE(method != nullptr); // Find the "interfaces" static field. This is generated for all proxies. ArtField* field = nullptr; for (size_t i = 0; i < proxyClass->NumStaticFields(); ++i) { ArtField* f = proxyClass->GetStaticField(i); if (strcmp("interfaces", f->GetName()) == 0) { field = f; break; } } ASSERT_TRUE(field != nullptr); // Test the signature. We expect the signature from the interface class. std::ostringstream ss_method; MemberSignature(method->GetInterfaceMethodIfProxy(kRuntimePointerSize)).Dump(ss_method); ASSERT_EQ("Lmypackage/packagea/Interface;->method()V", ss_method.str()); // Test the signature. We expect the signature of the proxy class. std::ostringstream ss_field; MemberSignature(field).Dump(ss_field); ASSERT_EQ("L$Proxy1234;->interfaces:[Ljava/lang/Class;", ss_field.str()); } TEST_F(HiddenApiTest, DexDomain_DataDir) { // Load file from a non-system directory and check that it is not flagged as framework. std::string data_location_path = android_data_ + "/foo.jar"; ASSERT_FALSE(LocationIsOnSystemFramework(data_location_path.c_str())); TestLocation(data_location_path, hiddenapi::Domain::kApplication); } TEST_F(HiddenApiTest, DexDomain_SystemDir) { // Load file from a system, non-framework directory and check that it is not flagged as framework. std::string system_location_path = GetAndroidRoot() + "/foo.jar"; ASSERT_FALSE(LocationIsOnSystemFramework(system_location_path.c_str())); TestLocation(system_location_path, hiddenapi::Domain::kApplication); } TEST_F(HiddenApiTest, DexDomain_SystemExtDir) { // Load file from a system_ext, non-framework directory and check that it is not flagged as // framework. std::string system_ext_location_path = android_system_ext_ + "/foo.jar"; ASSERT_FALSE(LocationIsOnSystemExtFramework(system_ext_location_path.c_str())); TestLocation(system_ext_location_path, hiddenapi::Domain::kApplication); } TEST_F(HiddenApiTest, DexDomain_SystemSystemExtDir) { // Load file from a system/system_ext, non-framework directory and check that it is not flagged as // framework. std::filesystem::create_directory(GetAndroidRoot() + "/system_ext"); std::string system_ext_location_path = GetAndroidRoot() + "/system_ext/foo.jar"; ASSERT_FALSE(LocationIsOnSystemExtFramework(system_ext_location_path.c_str())); TestLocation(system_ext_location_path, hiddenapi::Domain::kApplication); } TEST_F(HiddenApiTest, DexDomain_SystemFrameworkDir) { // Load file from a system/framework directory and check that it is flagged as a framework dex. std::filesystem::create_directory(GetAndroidRoot() + "/framework"); std::string system_framework_location_path = GetAndroidRoot() + "/framework/foo.jar"; ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_location_path.c_str())); TestLocation(system_framework_location_path, hiddenapi::Domain::kPlatform); } TEST_F(HiddenApiTest, DexDomain_SystemExtFrameworkDir) { // Load file from a system_ext/framework directory and check that it is flagged as a framework dex. std::filesystem::create_directory(android_system_ext_ + "/framework"); std::string system_ext_framework_location_path = android_system_ext_ + "/framework/foo.jar"; ASSERT_TRUE(LocationIsOnSystemExtFramework(system_ext_framework_location_path.c_str())); TestLocation(system_ext_framework_location_path, hiddenapi::Domain::kPlatform); } TEST_F(HiddenApiTest, DexDomain_SystemSystemExtFrameworkDir) { // Load file from a system/system_ext/framework directory and check that it is flagged as a // framework dex. std::filesystem::create_directory(GetAndroidRoot() + "/system_ext"); std::filesystem::create_directory(GetAndroidRoot() + "/system_ext/framework"); std::string system_ext_framework_location_path = GetAndroidRoot() + "/system_ext/framework/foo.jar"; ASSERT_TRUE(LocationIsOnSystemExtFramework(system_ext_framework_location_path.c_str())); TestLocation(system_ext_framework_location_path, hiddenapi::Domain::kPlatform); } TEST_F(HiddenApiTest, DexDomain_DataDir_MultiDex) { // Load multidex file from a non-system directory and check that it is not flagged as framework. std::string data_multi_location_path = android_data_ + "/multifoo.jar"; ASSERT_FALSE(LocationIsOnSystemFramework(data_multi_location_path.c_str())); TestLocation(data_multi_location_path, hiddenapi::Domain::kApplication); } TEST_F(HiddenApiTest, DexDomain_SystemDir_MultiDex) { // Load multidex file from a system, non-framework directory and check that it is not flagged // as framework. std::string system_multi_location_path = GetAndroidRoot() + "/multifoo.jar"; ASSERT_FALSE(LocationIsOnSystemFramework(system_multi_location_path.c_str())); TestLocation(system_multi_location_path, hiddenapi::Domain::kApplication); } TEST_F(HiddenApiTest, DexDomain_SystemExtDir_MultiDex) { // Load multidex file from a system_ext, non-framework directory and check that it is not flagged // as framework. std::string system_ext_multi_location_path = android_system_ext_ + "/multifoo.jar"; ASSERT_FALSE(LocationIsOnSystemExtFramework(system_ext_multi_location_path.c_str())); TestLocation(system_ext_multi_location_path, hiddenapi::Domain::kApplication); } TEST_F(HiddenApiTest, DexDomain_SystemSystemExtDir_MultiDex) { // Load multidex file from a system/system_ext, non-framework directory and check that it is not // flagged as framework. std::filesystem::create_directory(GetAndroidRoot() + "/system_ext"); std::string system_ext_multi_location_path = GetAndroidRoot() + "/system_ext/multifoo.jar"; ASSERT_FALSE(LocationIsOnSystemExtFramework(system_ext_multi_location_path.c_str())); TestLocation(system_ext_multi_location_path, hiddenapi::Domain::kApplication); } TEST_F(HiddenApiTest, DexDomain_SystemFrameworkDir_MultiDex) { // Load multidex file from a system/framework directory and check that it is flagged as a // framework dex. std::filesystem::create_directory(GetAndroidRoot() + "/framework"); std::string system_framework_multi_location_path = GetAndroidRoot() + "/framework/multifoo.jar"; ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_multi_location_path.c_str())); TestLocation(system_framework_multi_location_path, hiddenapi::Domain::kPlatform); } TEST_F(HiddenApiTest, DexDomain_SystemExtFrameworkDir_MultiDex) { // Load multidex file from a system_ext/framework directory and check that it is flagged as a // framework dex. std::filesystem::create_directory(android_system_ext_ + "/framework"); std::string system_ext_framework_multi_location_path = android_system_ext_ + "/framework/multifoo.jar"; ASSERT_TRUE(LocationIsOnSystemExtFramework(system_ext_framework_multi_location_path.c_str())); TestLocation(system_ext_framework_multi_location_path, hiddenapi::Domain::kPlatform); } TEST_F(HiddenApiTest, DexDomain_SystemSystemExtFrameworkDir_MultiDex) { // Load multidex file from a system/system_ext/framework directory and check that it is flagged // as a framework dex. std::filesystem::create_directory(GetAndroidRoot() + "/system_ext"); std::filesystem::create_directory(GetAndroidRoot() + "/system_ext/framework"); std::string system_ext_framework_multi_location_path = GetAndroidRoot() + "/system_ext/framework/multifoo.jar"; ASSERT_TRUE(LocationIsOnSystemExtFramework(system_ext_framework_multi_location_path.c_str())); TestLocation(system_ext_framework_multi_location_path, hiddenapi::Domain::kPlatform); } } // namespace art