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 21 #include "java_vm_ext.h" 22 #include "runtime.h" 23 24 namespace art { 25 namespace ti { 26 27 using android::base::StringPrintf; 28 29 const char* AGENT_ON_LOAD_FUNCTION_NAME = "Agent_OnLoad"; 30 const char* AGENT_ON_ATTACH_FUNCTION_NAME = "Agent_OnAttach"; 31 const char* AGENT_ON_UNLOAD_FUNCTION_NAME = "Agent_OnUnload"; 32 33 // TODO We need to acquire some locks probably. 34 Agent::LoadError Agent::DoLoadHelper(bool attaching, 35 /*out*/jint* call_res, 36 /*out*/std::string* error_msg) { 37 DCHECK(call_res != nullptr); 38 DCHECK(error_msg != nullptr); 39 40 if (IsStarted()) { 41 *error_msg = StringPrintf("the agent at %s has already been started!", name_.c_str()); 42 VLOG(agents) << "err: " << *error_msg; 43 return kAlreadyStarted; 44 } 45 LoadError err = DoDlOpen(error_msg); 46 if (err != kNoError) { 47 VLOG(agents) << "err: " << *error_msg; 48 return err; 49 } 50 AgentOnLoadFunction callback = attaching ? onattach_ : onload_; 51 if (callback == nullptr) { 52 *error_msg = StringPrintf("Unable to start agent %s: No %s callback found", 53 (attaching ? "attach" : "load"), 54 name_.c_str()); 55 VLOG(agents) << "err: " << *error_msg; 56 return kLoadingError; 57 } 58 // Need to let the function fiddle with the array. 59 std::unique_ptr<char[]> copied_args(new char[args_.size() + 1]); 60 strcpy(copied_args.get(), args_.c_str()); 61 // TODO Need to do some checks that we are at a good spot etc. 62 *call_res = callback(Runtime::Current()->GetJavaVM(), 63 copied_args.get(), 64 nullptr); 65 if (*call_res != 0) { 66 *error_msg = StringPrintf("Initialization of %s returned non-zero value of %d", 67 name_.c_str(), *call_res); 68 VLOG(agents) << "err: " << *error_msg; 69 return kInitializationError; 70 } else { 71 return kNoError; 72 } 73 } 74 75 void* Agent::FindSymbol(const std::string& name) const { 76 CHECK(IsStarted()) << "Cannot find symbols in an unloaded agent library " << this; 77 return dlsym(dlopen_handle_, name.c_str()); 78 } 79 80 Agent::LoadError Agent::DoDlOpen(/*out*/std::string* error_msg) { 81 DCHECK(error_msg != nullptr); 82 83 DCHECK(dlopen_handle_ == nullptr); 84 DCHECK(onload_ == nullptr); 85 DCHECK(onattach_ == nullptr); 86 DCHECK(onunload_ == nullptr); 87 88 dlopen_handle_ = dlopen(name_.c_str(), RTLD_LAZY); 89 if (dlopen_handle_ == nullptr) { 90 *error_msg = StringPrintf("Unable to dlopen %s: %s", name_.c_str(), dlerror()); 91 return kLoadingError; 92 } 93 94 onload_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_LOAD_FUNCTION_NAME)); 95 if (onload_ == nullptr) { 96 VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this; 97 } 98 onattach_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_ATTACH_FUNCTION_NAME)); 99 if (onattach_ == nullptr) { 100 VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this; 101 } 102 onunload_= reinterpret_cast<AgentOnUnloadFunction>(FindSymbol(AGENT_ON_UNLOAD_FUNCTION_NAME)); 103 if (onunload_ == nullptr) { 104 VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this; 105 } 106 return kNoError; 107 } 108 109 // TODO Lock some stuff probably. 110 void Agent::Unload() { 111 if (dlopen_handle_ != nullptr) { 112 if (onunload_ != nullptr) { 113 onunload_(Runtime::Current()->GetJavaVM()); 114 } 115 dlclose(dlopen_handle_); 116 dlopen_handle_ = nullptr; 117 onload_ = nullptr; 118 onattach_ = nullptr; 119 onunload_ = nullptr; 120 } else { 121 VLOG(agents) << this << " is not currently loaded!"; 122 } 123 } 124 125 Agent::Agent(std::string arg) 126 : dlopen_handle_(nullptr), 127 onload_(nullptr), 128 onattach_(nullptr), 129 onunload_(nullptr) { 130 size_t eq = arg.find_first_of('='); 131 if (eq == std::string::npos) { 132 name_ = arg; 133 } else { 134 name_ = arg.substr(0, eq); 135 args_ = arg.substr(eq + 1, arg.length()); 136 } 137 } 138 139 Agent::Agent(const Agent& other) 140 : dlopen_handle_(nullptr), 141 onload_(nullptr), 142 onattach_(nullptr), 143 onunload_(nullptr) { 144 *this = other; 145 } 146 147 // Attempting to copy to/from loaded/started agents is a fatal error 148 Agent& Agent::operator=(const Agent& other) { 149 if (this != &other) { 150 if (other.dlopen_handle_ != nullptr) { 151 LOG(FATAL) << "Attempting to copy a loaded agent!"; 152 } 153 154 if (dlopen_handle_ != nullptr) { 155 LOG(FATAL) << "Attempting to assign into a loaded agent!"; 156 } 157 158 DCHECK(other.onload_ == nullptr); 159 DCHECK(other.onattach_ == nullptr); 160 DCHECK(other.onunload_ == nullptr); 161 162 DCHECK(onload_ == nullptr); 163 DCHECK(onattach_ == nullptr); 164 DCHECK(onunload_ == nullptr); 165 166 name_ = other.name_; 167 args_ = other.args_; 168 169 dlopen_handle_ = nullptr; 170 onload_ = nullptr; 171 onattach_ = nullptr; 172 onunload_ = nullptr; 173 } 174 return *this; 175 } 176 177 Agent::Agent(Agent&& other) 178 : dlopen_handle_(nullptr), 179 onload_(nullptr), 180 onattach_(nullptr), 181 onunload_(nullptr) { 182 *this = std::move(other); 183 } 184 185 Agent& Agent::operator=(Agent&& other) { 186 if (this != &other) { 187 if (dlopen_handle_ != nullptr) { 188 dlclose(dlopen_handle_); 189 } 190 name_ = std::move(other.name_); 191 args_ = std::move(other.args_); 192 dlopen_handle_ = other.dlopen_handle_; 193 onload_ = other.onload_; 194 onattach_ = other.onattach_; 195 onunload_ = other.onunload_; 196 other.dlopen_handle_ = nullptr; 197 other.onload_ = nullptr; 198 other.onattach_ = nullptr; 199 other.onunload_ = nullptr; 200 } 201 return *this; 202 } 203 204 Agent::~Agent() { 205 if (dlopen_handle_ != nullptr) { 206 dlclose(dlopen_handle_); 207 } 208 } 209 210 std::ostream& operator<<(std::ostream &os, const Agent* m) { 211 return os << *m; 212 } 213 214 std::ostream& operator<<(std::ostream &os, Agent const& m) { 215 return os << "Agent { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\", handle=" 216 << m.dlopen_handle_ << " }"; 217 } 218 219 } // namespace ti 220 } // namespace art 221