1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "agent.h" 18 19 #include "android-base/stringprintf.h" 20 #include "nativehelper/scoped_local_ref.h" 21 #include "nativeloader/native_loader.h" 22 23 #include "base/logging.h" 24 #include "base/strlcpy.h" 25 #include "jni/java_vm_ext.h" 26 #include "runtime.h" 27 #include "thread-current-inl.h" 28 #include "scoped_thread_state_change-inl.h" 29 30 namespace art { 31 namespace ti { 32 33 using android::base::StringPrintf; 34 35 const char* AGENT_ON_LOAD_FUNCTION_NAME = "Agent_OnLoad"; 36 const char* AGENT_ON_ATTACH_FUNCTION_NAME = "Agent_OnAttach"; 37 const char* AGENT_ON_UNLOAD_FUNCTION_NAME = "Agent_OnUnload"; 38 39 AgentSpec::AgentSpec(const std::string& arg) { 40 size_t eq = arg.find_first_of('='); 41 if (eq == std::string::npos) { 42 name_ = arg; 43 } else { 44 name_ = arg.substr(0, eq); 45 args_ = arg.substr(eq + 1, arg.length()); 46 } 47 } 48 49 std::unique_ptr<Agent> AgentSpec::Load(/*out*/jint* call_res, 50 /*out*/LoadError* error, 51 /*out*/std::string* error_msg) { 52 VLOG(agents) << "Loading agent: " << name_ << " " << args_; 53 return DoLoadHelper(nullptr, false, nullptr, call_res, error, error_msg); 54 } 55 56 // Tries to attach the agent using its OnAttach method. Returns true on success. 57 std::unique_ptr<Agent> AgentSpec::Attach(JNIEnv* env, 58 jobject class_loader, 59 /*out*/jint* call_res, 60 /*out*/LoadError* error, 61 /*out*/std::string* error_msg) { 62 VLOG(agents) << "Attaching agent: " << name_ << " " << args_; 63 return DoLoadHelper(env, true, class_loader, call_res, error, error_msg); 64 } 65 66 67 // TODO We need to acquire some locks probably. 68 std::unique_ptr<Agent> AgentSpec::DoLoadHelper(JNIEnv* env, 69 bool attaching, 70 jobject class_loader, 71 /*out*/jint* call_res, 72 /*out*/LoadError* error, 73 /*out*/std::string* error_msg) { 74 ScopedThreadStateChange stsc(Thread::Current(), ThreadState::kNative); 75 DCHECK(call_res != nullptr); 76 DCHECK(error_msg != nullptr); 77 78 std::unique_ptr<Agent> agent = DoDlOpen(env, class_loader, error, error_msg); 79 if (agent == nullptr) { 80 VLOG(agents) << "err: " << *error_msg; 81 return nullptr; 82 } 83 AgentOnLoadFunction callback = attaching ? agent->onattach_ : agent->onload_; 84 if (callback == nullptr) { 85 *error_msg = StringPrintf("Unable to start agent %s: No %s callback found", 86 (attaching ? "attach" : "load"), 87 name_.c_str()); 88 VLOG(agents) << "err: " << *error_msg; 89 *error = kLoadingError; 90 return nullptr; 91 } 92 // Need to let the function fiddle with the array. 93 std::unique_ptr<char[]> copied_args(new char[args_.size() + 1]); 94 strlcpy(copied_args.get(), args_.c_str(), args_.size() + 1); 95 // TODO Need to do some checks that we are at a good spot etc. 96 *call_res = callback(Runtime::Current()->GetJavaVM(), 97 copied_args.get(), 98 nullptr); 99 if (*call_res != 0) { 100 *error_msg = StringPrintf("Initialization of %s returned non-zero value of %d", 101 name_.c_str(), *call_res); 102 VLOG(agents) << "err: " << *error_msg; 103 *error = kInitializationError; 104 return nullptr; 105 } 106 return agent; 107 } 108 109 std::unique_ptr<Agent> AgentSpec::DoDlOpen(JNIEnv* env, 110 jobject class_loader, 111 /*out*/LoadError* error, 112 /*out*/std::string* error_msg) { 113 DCHECK(error_msg != nullptr); 114 115 ScopedLocalRef<jstring> library_path(env, 116 class_loader == nullptr 117 ? nullptr 118 : JavaVMExt::GetLibrarySearchPath(env, class_loader)); 119 120 bool needs_native_bridge = false; 121 char* nativeloader_error_msg = nullptr; 122 void* dlopen_handle = android::OpenNativeLibrary(env, 123 Runtime::Current()->GetTargetSdkVersion(), 124 name_.c_str(), 125 class_loader, 126 nullptr, 127 library_path.get(), 128 &needs_native_bridge, 129 &nativeloader_error_msg); 130 if (dlopen_handle == nullptr) { 131 *error_msg = StringPrintf("Unable to dlopen %s: %s", 132 name_.c_str(), 133 nativeloader_error_msg); 134 android::NativeLoaderFreeErrorMessage(nativeloader_error_msg); 135 *error = kLoadingError; 136 return nullptr; 137 } 138 if (needs_native_bridge) { 139 // TODO: Consider support? 140 // The result of this call and error_msg is ignored because the most 141 // relevant error is that native bridge is unsupported. 142 android::CloseNativeLibrary(dlopen_handle, needs_native_bridge, &nativeloader_error_msg); 143 android::NativeLoaderFreeErrorMessage(nativeloader_error_msg); 144 *error_msg = StringPrintf("Native-bridge agents unsupported: %s", name_.c_str()); 145 *error = kLoadingError; 146 return nullptr; 147 } 148 149 std::unique_ptr<Agent> agent(new Agent(name_, dlopen_handle)); 150 agent->PopulateFunctions(); 151 *error = kNoError; 152 return agent; 153 } 154 155 std::ostream& operator<<(std::ostream &os, AgentSpec const& m) { 156 return os << "AgentSpec { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\" }"; 157 } 158 159 160 void* Agent::FindSymbol(const std::string& name) const { 161 CHECK(dlopen_handle_ != nullptr) << "Cannot find symbols in an unloaded agent library " << this; 162 return dlsym(dlopen_handle_, name.c_str()); 163 } 164 165 // TODO Lock some stuff probably. 166 void Agent::Unload() { 167 if (dlopen_handle_ != nullptr) { 168 if (onunload_ != nullptr) { 169 onunload_(Runtime::Current()->GetJavaVM()); 170 } 171 // Don't actually android::CloseNativeLibrary since some agents assume they will never get 172 // unloaded. Since this only happens when the runtime is shutting down anyway this isn't a big 173 // deal. 174 dlopen_handle_ = nullptr; 175 onload_ = nullptr; 176 onattach_ = nullptr; 177 onunload_ = nullptr; 178 } else { 179 VLOG(agents) << this << " is not currently loaded!"; 180 } 181 } 182 183 Agent::Agent(Agent&& other) noexcept 184 : dlopen_handle_(nullptr), 185 onload_(nullptr), 186 onattach_(nullptr), 187 onunload_(nullptr) { 188 *this = std::move(other); 189 } 190 191 Agent& Agent::operator=(Agent&& other) noexcept { 192 if (this != &other) { 193 if (dlopen_handle_ != nullptr) { 194 Unload(); 195 } 196 name_ = std::move(other.name_); 197 dlopen_handle_ = other.dlopen_handle_; 198 onload_ = other.onload_; 199 onattach_ = other.onattach_; 200 onunload_ = other.onunload_; 201 other.dlopen_handle_ = nullptr; 202 other.onload_ = nullptr; 203 other.onattach_ = nullptr; 204 other.onunload_ = nullptr; 205 } 206 return *this; 207 } 208 209 void Agent::PopulateFunctions() { 210 onload_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_LOAD_FUNCTION_NAME)); 211 if (onload_ == nullptr) { 212 VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this; 213 } 214 onattach_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_ATTACH_FUNCTION_NAME)); 215 if (onattach_ == nullptr) { 216 VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this; 217 } 218 onunload_ = reinterpret_cast<AgentOnUnloadFunction>(FindSymbol(AGENT_ON_UNLOAD_FUNCTION_NAME)); 219 if (onunload_ == nullptr) { 220 VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this; 221 } 222 } 223 224 Agent::~Agent() { 225 if (dlopen_handle_ != nullptr) { 226 Unload(); 227 } 228 } 229 230 std::ostream& operator<<(std::ostream &os, const Agent* m) { 231 return os << *m; 232 } 233 234 std::ostream& operator<<(std::ostream &os, Agent const& m) { 235 return os << "Agent { name=\"" << m.name_ << "\", handle=" << m.dlopen_handle_ << " }"; 236 } 237 238 } // namespace ti 239 } // namespace art 240