diff options
-rw-r--r-- | compiler/image_writer.cc | 3 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 84 | ||||
-rw-r--r-- | compiler/oat_writer.h | 1 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 16 | ||||
-rw-r--r-- | runtime/jit/profile_saver.cc | 6 | ||||
-rw-r--r-- | runtime/mirror/class-inl.h | 2 | ||||
-rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 25 | ||||
-rw-r--r-- | runtime/oat_file_assistant.cc | 4 | ||||
-rw-r--r-- | runtime/oat_file_assistant.h | 4 | ||||
-rw-r--r-- | runtime/oat_file_manager.cc | 30 | ||||
-rw-r--r-- | test/601-method-access/expected.txt | 1 | ||||
-rw-r--r-- | test/601-method-access/info.txt | 1 | ||||
-rw-r--r-- | test/601-method-access/smali/SubClassUsingInaccessibleMethod.smali | 33 | ||||
-rw-r--r-- | test/601-method-access/src/Main.java | 38 | ||||
-rw-r--r-- | test/601-method-access/src/other/ProtectedClass.java | 24 | ||||
-rw-r--r-- | test/601-method-access/src/other/PublicClass.java | 21 |
16 files changed, 238 insertions, 55 deletions
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index be720ad2f3..eaeacc59dd 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -437,6 +437,9 @@ void ImageWriter::PrepareDexCacheArraySlots() { continue; } const DexFile* dex_file = dex_cache->GetDexFile(); + CHECK(dex_file_oat_index_map_.find(dex_file) != dex_file_oat_index_map_.end()) + << "Dex cache should have been pruned " << dex_file->GetLocation() + << "; possibly in class path"; DexCacheArraysLayout layout(target_ptr_size_, dex_file); DCHECK(layout.Valid()); size_t oat_index = GetOatIndexForDexCache(dex_cache); diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 41d30fd539..a02c0247b7 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -63,6 +63,29 @@ const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data); } +class ChecksumUpdatingOutputStream : public OutputStream { + public: + ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header) + : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { } + + bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE { + oat_header_->UpdateChecksum(buffer, byte_count); + return out_->WriteFully(buffer, byte_count); + } + + off_t Seek(off_t offset, Whence whence) OVERRIDE { + return out_->Seek(offset, whence); + } + + bool Flush() OVERRIDE { + return out_->Flush(); + } + + private: + OutputStream* const out_; + OatHeader* const oat_header_; +}; + } // anonymous namespace // Defines the location of the raw dex file to write. @@ -422,13 +445,21 @@ bool OatWriter::WriteAndOpenDexFiles( for (OatDexFile& oat_dex_file : oat_dex_files_) { oat_dex_file.ReserveClassOffsets(this); } - if (!WriteOatDexFiles(rodata) || + ChecksumUpdatingOutputStream checksum_updating_rodata(rodata, oat_header_.get()); + if (!WriteOatDexFiles(&checksum_updating_rodata) || !ExtendForTypeLookupTables(rodata, file, size_after_type_lookup_tables) || !OpenDexFiles(file, verify, &dex_files_map, &dex_files) || !WriteTypeLookupTables(dex_files_map.get(), dex_files)) { return false; } + // Do a bulk checksum update for Dex[] and TypeLookupTable[]. Doing it piece by + // piece would be difficult because we're not using the OutpuStream directly. + if (!oat_dex_files_.empty()) { + size_t size = size_after_type_lookup_tables - oat_dex_files_[0].dex_file_offset_; + oat_header_->UpdateChecksum(dex_files_map->Begin(), size); + } + *opened_dex_files_map = std::move(dex_files_map); *opened_dex_files = std::move(dex_files); write_state_ = WriteState::kPrepareLayout; @@ -996,7 +1027,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { << PrettyMethod(it.GetMemberIndex(), *dex_file_); const OatQuickMethodHeader& method_header = oat_class->method_headers_[method_offsets_index_]; - if (!writer_->WriteData(out, &method_header, sizeof(method_header))) { + if (!out->WriteFully(&method_header, sizeof(method_header))) { ReportWriteFailure("method header", it); return false; } @@ -1063,7 +1094,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } } - if (!writer_->WriteData(out, quick_code.data(), code_size)) { + if (!out->WriteFully(quick_code.data(), code_size)) { ReportWriteFailure("method code", it); return false; } @@ -1273,7 +1304,7 @@ class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { size_t map_size = map.size() * sizeof(map[0]); if (map_offset == offset_) { // Write deduplicated map (code info for Optimizing or transformation info for dex2dex). - if (UNLIKELY(!writer_->WriteData(out, map.data(), map_size))) { + if (UNLIKELY(!out->WriteFully(map.data(), map_size))) { ReportWriteFailure(it); return false; } @@ -1451,6 +1482,10 @@ size_t OatWriter::InitOatCodeDexFiles(size_t offset) { bool OatWriter::WriteRodata(OutputStream* out) { CHECK(write_state_ == WriteState::kWriteRoData); + // Wrap out to update checksum with each write. + ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get()); + out = &checksum_updating_out; + if (!WriteClassOffsets(out)) { LOG(ERROR) << "Failed to write class offsets to " << out->GetLocation(); return false; @@ -1493,6 +1528,10 @@ bool OatWriter::WriteRodata(OutputStream* out) { bool OatWriter::WriteCode(OutputStream* out) { CHECK(write_state_ == WriteState::kWriteText); + // Wrap out to update checksum with each write. + ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get()); + out = &checksum_updating_out; + SetMultiOatRelativePatcherAdjustment(); const size_t file_offset = oat_data_offset_; @@ -1677,7 +1716,7 @@ size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t uint32_t alignment_padding = aligned_offset - relative_offset; \ out->Seek(alignment_padding, kSeekCurrent); \ size_trampoline_alignment_ += alignment_padding; \ - if (!WriteData(out, field->data(), field->size())) { \ + if (!out->WriteFully(field->data(), field->size())) { \ PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \ return false; \ } \ @@ -2007,7 +2046,7 @@ bool OatWriter::WriteDexFile(OutputStream* rodata, DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation())); const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file); - if (!WriteData(rodata, dex_file, header->file_size_)) { + if (!rodata->WriteFully(dex_file, header->file_size_)) { PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation() << " to " << rodata->GetLocation(); return false; @@ -2187,18 +2226,13 @@ bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delt 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; DCHECK_LE(aligned_code_delta, sizeof(kPadding)); - if (UNLIKELY(!WriteData(out, kPadding, aligned_code_delta))) { + if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) { return false; } size_code_alignment_ += aligned_code_delta; return true; } -bool OatWriter::WriteData(OutputStream* out, const void* data, size_t size) { - oat_header_->UpdateChecksum(data, size); - return out->WriteFully(data, size); -} - void OatWriter::SetMultiOatRelativePatcherAdjustment() { DCHECK(dex_files_ != nullptr); DCHECK(relative_patcher_ != nullptr); @@ -2268,39 +2302,37 @@ bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) cons const size_t file_offset = oat_writer->oat_data_offset_; DCHECK_OFFSET_(); - if (!oat_writer->WriteData(out, &dex_file_location_size_, sizeof(dex_file_location_size_))) { + if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) { PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_); - if (!oat_writer->WriteData(out, dex_file_location_data_, dex_file_location_size_)) { + if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) { PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_; - if (!oat_writer->WriteData(out, - &dex_file_location_checksum_, - sizeof(dex_file_location_checksum_))) { + if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) { PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_); - if (!oat_writer->WriteData(out, &dex_file_offset_, sizeof(dex_file_offset_))) { + if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) { PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_); - if (!oat_writer->WriteData(out, &class_offsets_offset_, sizeof(class_offsets_offset_))) { + if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) { PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_); - if (!oat_writer->WriteData(out, &lookup_table_offset_, sizeof(lookup_table_offset_))) { + if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) { PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation(); return false; } @@ -2310,7 +2342,7 @@ bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) cons } bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) { - if (!oat_writer->WriteData(out, class_offsets_.data(), GetClassOffsetsRawSize())) { + if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) { PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation() << " to " << out->GetLocation(); return false; @@ -2399,13 +2431,13 @@ bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const { DCHECK_OFFSET_(); - if (!oat_writer->WriteData(out, &status_, sizeof(status_))) { + if (!out->WriteFully(&status_, sizeof(status_))) { PLOG(ERROR) << "Failed to write class status to " << out->GetLocation(); return false; } oat_writer->size_oat_class_status_ += sizeof(status_); - if (!oat_writer->WriteData(out, &type_, sizeof(type_))) { + if (!out->WriteFully(&type_, sizeof(type_))) { PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation(); return false; } @@ -2413,20 +2445,20 @@ bool OatWriter::OatClass::Write(OatWriter* oat_writer, if (method_bitmap_size_ != 0) { CHECK_EQ(kOatClassSomeCompiled, type_); - if (!oat_writer->WriteData(out, &method_bitmap_size_, sizeof(method_bitmap_size_))) { + if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) { PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation(); return false; } oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_); - if (!oat_writer->WriteData(out, method_bitmap_->GetRawStorage(), method_bitmap_size_)) { + if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) { PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation(); return false; } oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_; } - if (!oat_writer->WriteData(out, method_offsets_.data(), GetMethodOffsetsRawSize())) { + if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) { PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation(); return false; } diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 3862798329..cc81f39f36 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -271,7 +271,6 @@ class OatWriter { bool WriteTypeLookupTables(MemMap* opened_dex_files_map, const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files); bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta); - bool WriteData(OutputStream* out, const void* data, size_t size); void SetMultiOatRelativePatcherAdjustment(); enum class WriteState { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 9f6f4530c7..cce83f32b5 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1269,6 +1269,21 @@ class Dex2Oat FINAL { CHECK(runtime != nullptr); std::set<DexCacheResolvedClasses> resolved_classes( profile_compilation_info_->GetResolvedClasses()); + + // Filter out class path classes since we don't want to include these in the image. + std::unordered_set<std::string> dex_files_locations; + for (const DexFile* dex_file : dex_files_) { + dex_files_locations.insert(dex_file->GetLocation()); + } + for (auto it = resolved_classes.begin(); it != resolved_classes.end(); ) { + if (dex_files_locations.find(it->GetDexLocation()) == dex_files_locations.end()) { + VLOG(compiler) << "Removed profile samples for non-app dex file " << it->GetDexLocation(); + it = resolved_classes.erase(it); + } else { + ++it; + } + } + image_classes_.reset(new std::unordered_set<std::string>( runtime->GetClassLinker()->GetClassDescriptorsForProfileKeys(resolved_classes))); VLOG(compiler) << "Loaded " << image_classes_->size() @@ -2443,6 +2458,7 @@ class Dex2Oat FINAL { bool multi_image_; bool is_host_; std::string android_root_; + // Dex files we are compiling, does not include the class path dex files. std::vector<const DexFile*> dex_files_; std::string no_inline_from_string_; std::vector<jobject> dex_caches_; diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc index c5d3ccd748..9822f6e851 100644 --- a/runtime/jit/profile_saver.cc +++ b/runtime/jit/profile_saver.cc @@ -120,7 +120,7 @@ void ProfileSaver::Run() { { MutexLock mu(self, wait_lock_); period_condition_.Wait(self); - sleep_time = NanoTime() - last_time_ns_saver_woke_up_; + sleep_time = NanoTime() - sleep_start; } // Check if the thread was woken up for shutdown. if (ShuttingDown(self)) { @@ -130,11 +130,11 @@ void ProfileSaver::Run() { // We might have been woken up by a huge number of notifications to guarantee saving. // If we didn't meet the minimum saving period go back to sleep (only if missed by // a reasonable margin). - while (kMinSavePeriodNs - sleep_time > (kMinSavePeriodNs / 10)) { + while (kMinSavePeriodNs * 0.9 > sleep_time) { { MutexLock mu(self, wait_lock_); period_condition_.TimedWait(self, NsToMs(kMinSavePeriodNs - sleep_time), 0); - sleep_time = NanoTime() - last_time_ns_saver_woke_up_; + sleep_time = NanoTime() - sleep_start; } // Check if the thread was woken up for shutdown. if (ShuttingDown(self)) { diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index dfb728f00e..fcdfc88495 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -419,8 +419,6 @@ inline bool Class::ResolvedMethodAccessTest(Class* access_to, ArtMethod* method, } return false; } - DCHECK_EQ(this->CanAccessMember(access_to, method->GetAccessFlags()), - this->CanAccessMember(dex_access_to, method->GetAccessFlags())); } if (LIKELY(this->CanAccessMember(access_to, method->GetAccessFlags()))) { return true; diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 0126b4d0a4..f30f7a641e 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -475,15 +475,22 @@ static jint DexFile_getDexOptNeeded(JNIEnv* env, // public API static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) { - const char* instruction_set = GetInstructionSetString(kRuntimeISA); - ScopedUtfChars filename(env, javaFilename); - jint status = GetDexOptNeeded( - env, - filename.c_str(), - instruction_set, - "speed-profile", - /*profile_changed*/false); - return (status != OatFileAssistant::kNoDexOptNeeded) ? JNI_TRUE : JNI_FALSE; + ScopedUtfChars filename_utf(env, javaFilename); + if (env->ExceptionCheck()) { + return JNI_FALSE; + } + + const char* filename = filename_utf.c_str(); + if ((filename == nullptr) || !OS::FileExists(filename)) { + LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename << "' does not exist"; + ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException")); + const char* message = (filename == nullptr) ? "<empty file name>" : filename; + env->ThrowNew(fnfe.get(), message); + return JNI_FALSE; + } + + OatFileAssistant oat_file_assistant(filename, kRuntimeISA, false, false); + return oat_file_assistant.IsUpToDate() ? JNI_FALSE : JNI_TRUE; } static jboolean DexFile_isValidCompilerFilter(JNIEnv* env, diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 28fd9b98cd..c998e20ea9 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -198,6 +198,10 @@ OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded(CompilerFilter: return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded; } +bool OatFileAssistant::IsUpToDate() { + return OatFileIsUpToDate() || OdexFileIsUpToDate(); +} + OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::MakeUpToDate(CompilerFilter::Filter target, std::string* error_msg) { switch (GetDexOptNeeded(target)) { diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 34925cdae6..63d5022cca 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -149,6 +149,10 @@ class OatFileAssistant { // given compiler filter. DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter); + // Returns true if there is up-to-date code for this dex location, + // irrespective of the compiler filter of the up-to-date code. + bool IsUpToDate(); + // Return code used when attempting to generate updated code. enum ResultOfAttemptToUpdate { kUpdateFailed, // We tried making the code up to date, but diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 8bebf801c6..aff479f15e 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -588,22 +588,24 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( const OatFile* source_oat_file = nullptr; - // Update the oat file on disk if we can. This may fail, but that's okay. - // Best effort is all that matters here. - switch (oat_file_assistant.MakeUpToDate(filter_, /*out*/ &error_msg)) { - case OatFileAssistant::kUpdateFailed: - LOG(WARNING) << error_msg; - break; + if (!oat_file_assistant.IsUpToDate()) { + // Update the oat file on disk if we can. This may fail, but that's okay. + // Best effort is all that matters here. + switch (oat_file_assistant.MakeUpToDate(filter_, /*out*/ &error_msg)) { + case OatFileAssistant::kUpdateFailed: + LOG(WARNING) << error_msg; + break; - case OatFileAssistant::kUpdateNotAttempted: - // Avoid spamming the logs if we decided not to attempt making the oat - // file up to date. - VLOG(oat) << error_msg; - break; + case OatFileAssistant::kUpdateNotAttempted: + // Avoid spamming the logs if we decided not to attempt making the oat + // file up to date. + VLOG(oat) << error_msg; + break; - case OatFileAssistant::kUpdateSucceeded: - // Nothing to do. - break; + case OatFileAssistant::kUpdateSucceeded: + // Nothing to do. + break; + } } // Get the oat file on disk. diff --git a/test/601-method-access/expected.txt b/test/601-method-access/expected.txt new file mode 100644 index 0000000000..90fbab87af --- /dev/null +++ b/test/601-method-access/expected.txt @@ -0,0 +1 @@ +Got expected failure diff --git a/test/601-method-access/info.txt b/test/601-method-access/info.txt new file mode 100644 index 0000000000..e38a336179 --- /dev/null +++ b/test/601-method-access/info.txt @@ -0,0 +1 @@ +Regression test for method access checks. diff --git a/test/601-method-access/smali/SubClassUsingInaccessibleMethod.smali b/test/601-method-access/smali/SubClassUsingInaccessibleMethod.smali new file mode 100644 index 0000000000..7a896a2b8d --- /dev/null +++ b/test/601-method-access/smali/SubClassUsingInaccessibleMethod.smali @@ -0,0 +1,33 @@ +# Copyright (C) 2016 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 public LSubClassUsingInaccessibleMethod; + +.super Lother/PublicClass; + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Lother/PublicClass;-><init>()V + return-void +.end method + +# Regression test for compiler DCHECK() failure (bogus check) when referencing +# a package-private method from an indirectly inherited package-private class, +# using this very class as the declaring class in the MethodId, bug: 28771056. +.method public test()I + .registers 2 + invoke-virtual {p0}, LSubClassUsingInaccessibleMethod;->otherProtectedClassPackageIntInstanceMethod()I + move-result v0 + return v0 +.end method diff --git a/test/601-method-access/src/Main.java b/test/601-method-access/src/Main.java new file mode 100644 index 0000000000..838080a506 --- /dev/null +++ b/test/601-method-access/src/Main.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 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.lang.reflect.InvocationTargetException; + +/* + * Test method access through reflection. + */ +public class Main { + public static void main(String[] args) { + try { + Class c = Class.forName("SubClassUsingInaccessibleMethod"); + Object o = c.newInstance(); + c.getMethod("test").invoke(o, null); + } catch (InvocationTargetException ite) { + if (ite.getCause() instanceof IllegalAccessError) { + System.out.println("Got expected failure"); + } else { + System.out.println("Got unexpected failure " + ite.getCause()); + } + } catch (Exception e) { + System.out.println("Got unexpected failure " + e); + } + } +} diff --git a/test/601-method-access/src/other/ProtectedClass.java b/test/601-method-access/src/other/ProtectedClass.java new file mode 100644 index 0000000000..9426884c07 --- /dev/null +++ b/test/601-method-access/src/other/ProtectedClass.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 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. + */ + +package other; + +// Class that cannot be accessed outside of this package. +class ProtectedClass { + /* package */ int otherProtectedClassPackageIntInstanceMethod() { + return 28; + } +} diff --git a/test/601-method-access/src/other/PublicClass.java b/test/601-method-access/src/other/PublicClass.java new file mode 100644 index 0000000000..d9f79610c5 --- /dev/null +++ b/test/601-method-access/src/other/PublicClass.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 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. + */ + +package other; + +// Class that makes the ProtectedClass sub-classable by classes outside of package other. +public class PublicClass extends ProtectedClass { +} |