1 /* Copyright (C) 2017 The Android Open Source Project 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This file implements interfaces from the file jvmti.h. This implementation 5 * is licensed under the same terms as the file jvmti.h. The 6 * copyright and license information for the file jvmti.h follows. 7 * 8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10 * 11 * This code is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License version 2 only, as 13 * published by the Free Software Foundation. Oracle designates this 14 * particular file as subject to the "Classpath" exception as provided 15 * by Oracle in the LICENSE file that accompanied this code. 16 * 17 * This code is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20 * version 2 for more details (a copy is included in the LICENSE file that 21 * accompanied this code). 22 * 23 * You should have received a copy of the GNU General Public License version 24 * 2 along with this work; if not, write to the Free Software Foundation, 25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 26 * 27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 28 * or visit www.oracle.com if you need additional information or have any 29 * questions. 30 */ 31 32 #include "ti_search.h" 33 34 #include "jni.h" 35 36 #include "art_field-inl.h" 37 #include "art_jvmti.h" 38 #include "base/enums.h" 39 #include "base/macros.h" 40 #include "class_linker.h" 41 #include "dex_file.h" 42 #include "jni_internal.h" 43 #include "mirror/class-inl.h" 44 #include "mirror/object.h" 45 #include "mirror/string.h" 46 #include "obj_ptr-inl.h" 47 #include "runtime.h" 48 #include "runtime_callbacks.h" 49 #include "scoped_thread_state_change-inl.h" 50 #include "ScopedLocalRef.h" 51 #include "ti_phase.h" 52 #include "thread-inl.h" 53 #include "thread_list.h" 54 #include "well_known_classes.h" 55 56 namespace openjdkjvmti { 57 58 static std::vector<std::string> gSystemOnloadSegments; 59 60 static art::ObjPtr<art::mirror::Object> GetSystemProperties(art::Thread* self, 61 art::ClassLinker* class_linker) 62 REQUIRES_SHARED(art::Locks::mutator_lock_) { 63 art::ObjPtr<art::mirror::Class> system_class = 64 class_linker->LookupClass(self, "Ljava/lang/System;", nullptr); 65 DCHECK(system_class != nullptr); 66 DCHECK(system_class->IsInitialized()); 67 68 art::ArtField* props_field = 69 system_class->FindDeclaredStaticField("props", "Ljava/util/Properties;"); 70 DCHECK(props_field != nullptr); 71 72 art::ObjPtr<art::mirror::Object> props_obj = props_field->GetObject(system_class); 73 DCHECK(props_obj != nullptr); 74 75 return props_obj; 76 } 77 78 static void Update() REQUIRES_SHARED(art::Locks::mutator_lock_) { 79 if (gSystemOnloadSegments.empty()) { 80 return; 81 } 82 83 // In the on-load phase we have to modify java.class.path to influence the system classloader. 84 // As this is an unmodifiable system property, we have to access the "defaults" field. 85 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker(); 86 DCHECK(class_linker != nullptr); 87 art::Thread* self = art::Thread::Current(); 88 89 // Prepare: collect classes, fields and methods. 90 art::ObjPtr<art::mirror::Class> properties_class = 91 class_linker->LookupClass(self, "Ljava/util/Properties;", nullptr); 92 DCHECK(properties_class != nullptr); 93 94 ScopedLocalRef<jobject> defaults_jobj(self->GetJniEnv(), nullptr); 95 { 96 art::ObjPtr<art::mirror::Object> props_obj = GetSystemProperties(self, class_linker); 97 98 art::ArtField* defaults_field = 99 properties_class->FindDeclaredInstanceField("defaults", "Ljava/util/Properties;"); 100 DCHECK(defaults_field != nullptr); 101 102 art::ObjPtr<art::mirror::Object> defaults_obj = defaults_field->GetObject(props_obj); 103 DCHECK(defaults_obj != nullptr); 104 defaults_jobj.reset(self->GetJniEnv()->AddLocalReference<jobject>(defaults_obj)); 105 } 106 107 art::ArtMethod* get_property = 108 properties_class->FindDeclaredVirtualMethod( 109 "getProperty", 110 "(Ljava/lang/String;)Ljava/lang/String;", 111 art::kRuntimePointerSize); 112 DCHECK(get_property != nullptr); 113 art::ArtMethod* set_property = 114 properties_class->FindDeclaredVirtualMethod( 115 "setProperty", 116 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;", 117 art::kRuntimePointerSize); 118 DCHECK(set_property != nullptr); 119 120 // This is an allocation. Do this late to avoid the need for handles. 121 ScopedLocalRef<jobject> cp_jobj(self->GetJniEnv(), nullptr); 122 { 123 art::ObjPtr<art::mirror::Object> cp_key = 124 art::mirror::String::AllocFromModifiedUtf8(self, "java.class.path"); 125 if (cp_key == nullptr) { 126 self->AssertPendingOOMException(); 127 self->ClearException(); 128 return; 129 } 130 cp_jobj.reset(self->GetJniEnv()->AddLocalReference<jobject>(cp_key)); 131 } 132 133 // OK, now get the current value. 134 std::string str_value; 135 { 136 ScopedLocalRef<jobject> old_value(self->GetJniEnv(), 137 self->GetJniEnv()->CallObjectMethod( 138 defaults_jobj.get(), 139 art::jni::EncodeArtMethod(get_property), 140 cp_jobj.get())); 141 DCHECK(old_value.get() != nullptr); 142 143 str_value = self->DecodeJObject(old_value.get())->AsString()->ToModifiedUtf8(); 144 self->GetJniEnv()->DeleteLocalRef(old_value.release()); 145 } 146 147 // Update the value by appending the new segments. 148 for (const std::string& segment : gSystemOnloadSegments) { 149 if (!str_value.empty()) { 150 str_value += ":"; 151 } 152 str_value += segment; 153 } 154 gSystemOnloadSegments.clear(); 155 156 // Create the new value object. 157 ScopedLocalRef<jobject> new_val_jobj(self->GetJniEnv(), nullptr); 158 { 159 art::ObjPtr<art::mirror::Object> new_value = 160 art::mirror::String::AllocFromModifiedUtf8(self, str_value.c_str()); 161 if (new_value == nullptr) { 162 self->AssertPendingOOMException(); 163 self->ClearException(); 164 return; 165 } 166 167 new_val_jobj.reset(self->GetJniEnv()->AddLocalReference<jobject>(new_value)); 168 } 169 170 // Write to the defaults. 171 ScopedLocalRef<jobject> res_obj(self->GetJniEnv(), 172 self->GetJniEnv()->CallObjectMethod(defaults_jobj.get(), 173 art::jni::EncodeArtMethod(set_property), 174 cp_jobj.get(), 175 new_val_jobj.get())); 176 if (self->IsExceptionPending()) { 177 self->ClearException(); 178 return; 179 } 180 } 181 182 struct SearchCallback : public art::RuntimePhaseCallback { 183 void NextRuntimePhase(RuntimePhase phase) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { 184 if (phase == RuntimePhase::kStart) { 185 // It's time to update the system properties. 186 Update(); 187 } 188 } 189 }; 190 191 static SearchCallback gSearchCallback; 192 193 void SearchUtil::Register() { 194 art::Runtime* runtime = art::Runtime::Current(); 195 196 art::ScopedThreadStateChange stsc(art::Thread::Current(), 197 art::ThreadState::kWaitingForDebuggerToAttach); 198 art::ScopedSuspendAll ssa("Add search callback"); 199 runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gSearchCallback); 200 } 201 202 void SearchUtil::Unregister() { 203 art::ScopedThreadStateChange stsc(art::Thread::Current(), 204 art::ThreadState::kWaitingForDebuggerToAttach); 205 art::ScopedSuspendAll ssa("Remove search callback"); 206 art::Runtime* runtime = art::Runtime::Current(); 207 runtime->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&gSearchCallback); 208 } 209 210 jvmtiError SearchUtil::AddToBootstrapClassLoaderSearch(jvmtiEnv* env ATTRIBUTE_UNUSED, 211 const char* segment) { 212 art::Runtime* current = art::Runtime::Current(); 213 if (current == nullptr) { 214 return ERR(WRONG_PHASE); 215 } 216 if (current->GetClassLinker() == nullptr) { 217 return ERR(WRONG_PHASE); 218 } 219 if (segment == nullptr) { 220 return ERR(NULL_POINTER); 221 } 222 223 std::string error_msg; 224 std::vector<std::unique_ptr<const art::DexFile>> dex_files; 225 if (!art::DexFile::Open(segment, segment, true, &error_msg, &dex_files)) { 226 LOG(WARNING) << "Could not open " << segment << " for boot classpath extension: " << error_msg; 227 return ERR(ILLEGAL_ARGUMENT); 228 } 229 230 art::ScopedObjectAccess soa(art::Thread::Current()); 231 for (std::unique_ptr<const art::DexFile>& dex_file : dex_files) { 232 current->GetClassLinker()->AppendToBootClassPath(art::Thread::Current(), *dex_file.release()); 233 } 234 235 return ERR(NONE); 236 } 237 238 jvmtiError SearchUtil::AddToSystemClassLoaderSearch(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, 239 const char* segment) { 240 if (segment == nullptr) { 241 return ERR(NULL_POINTER); 242 } 243 244 jvmtiPhase phase = PhaseUtil::GetPhaseUnchecked(); 245 246 if (phase == jvmtiPhase::JVMTI_PHASE_ONLOAD) { 247 // We could try and see whether it is a valid path. We could also try to allocate Java 248 // objects to avoid later OOME. 249 gSystemOnloadSegments.push_back(segment); 250 return ERR(NONE); 251 } else if (phase != jvmtiPhase::JVMTI_PHASE_LIVE) { 252 return ERR(WRONG_PHASE); 253 } 254 255 jobject sys_class_loader = art::Runtime::Current()->GetSystemClassLoader(); 256 if (sys_class_loader == nullptr) { 257 // This is unexpected. 258 return ERR(INTERNAL); 259 } 260 261 // We'll use BaseDexClassLoader.addDexPath, as it takes care of array resizing etc. As a downside, 262 // exceptions are swallowed. 263 264 art::Thread* self = art::Thread::Current(); 265 JNIEnv* env = self->GetJniEnv(); 266 if (!env->IsInstanceOf(sys_class_loader, 267 art::WellKnownClasses::dalvik_system_BaseDexClassLoader)) { 268 return ERR(INTERNAL); 269 } 270 271 jmethodID add_dex_path_id = env->GetMethodID( 272 art::WellKnownClasses::dalvik_system_BaseDexClassLoader, 273 "addDexPath", 274 "(Ljava/lang/String;)V"); 275 if (add_dex_path_id == nullptr) { 276 return ERR(INTERNAL); 277 } 278 279 ScopedLocalRef<jstring> dex_path(env, env->NewStringUTF(segment)); 280 if (dex_path.get() == nullptr) { 281 return ERR(INTERNAL); 282 } 283 env->CallVoidMethod(sys_class_loader, add_dex_path_id, dex_path.get()); 284 285 if (env->ExceptionCheck()) { 286 env->ExceptionClear(); 287 return ERR(ILLEGAL_ARGUMENT); 288 } 289 return ERR(NONE); 290 } 291 292 } // namespace openjdkjvmti 293