blob: 15c514e5937166b0144fd5325073ea081835d53d [file] [log] [blame]
Alex Light7233c7e2016-07-28 10:07:45 -07001/*
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"
Andreas Gampe46ee31b2016-12-14 10:11:49 -080018
19#include "android-base/stringprintf.h"
Andreas Gampe7b38e692017-12-28 19:18:28 -080020#include "nativehelper/scoped_local_ref.h"
21#include "nativeloader/native_loader.h"
Andreas Gampe46ee31b2016-12-14 10:11:49 -080022
Andreas Gampef45d61c2017-06-07 10:29:33 -070023#include "base/strlcpy.h"
Alex Light7233c7e2016-07-28 10:07:45 -070024#include "java_vm_ext.h"
25#include "runtime.h"
Alex Lightb284f8d2017-11-21 00:00:48 +000026#include "thread-current-inl.h"
27#include "scoped_thread_state_change-inl.h"
Alex Light7233c7e2016-07-28 10:07:45 -070028
29namespace art {
30namespace ti {
31
Andreas Gampe46ee31b2016-12-14 10:11:49 -080032using android::base::StringPrintf;
33
Alex Light7233c7e2016-07-28 10:07:45 -070034const char* AGENT_ON_LOAD_FUNCTION_NAME = "Agent_OnLoad";
35const char* AGENT_ON_ATTACH_FUNCTION_NAME = "Agent_OnAttach";
36const char* AGENT_ON_UNLOAD_FUNCTION_NAME = "Agent_OnUnload";
37
Andreas Gampeaadcbc62017-12-28 14:05:42 -080038AgentSpec::AgentSpec(const std::string& arg) {
39 size_t eq = arg.find_first_of('=');
40 if (eq == std::string::npos) {
41 name_ = arg;
42 } else {
43 name_ = arg.substr(0, eq);
44 args_ = arg.substr(eq + 1, arg.length());
45 }
46}
47
48std::unique_ptr<Agent> AgentSpec::Load(/*out*/jint* call_res,
49 /*out*/LoadError* error,
50 /*out*/std::string* error_msg) {
51 VLOG(agents) << "Loading agent: " << name_ << " " << args_;
Andreas Gampe7b38e692017-12-28 19:18:28 -080052 return DoLoadHelper(nullptr, false, nullptr, call_res, error, error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -080053}
54
55// Tries to attach the agent using its OnAttach method. Returns true on success.
Andreas Gampe7b38e692017-12-28 19:18:28 -080056std::unique_ptr<Agent> AgentSpec::Attach(JNIEnv* env,
57 jobject class_loader,
58 /*out*/jint* call_res,
Andreas Gampeaadcbc62017-12-28 14:05:42 -080059 /*out*/LoadError* error,
60 /*out*/std::string* error_msg) {
61 VLOG(agents) << "Attaching agent: " << name_ << " " << args_;
Andreas Gampe7b38e692017-12-28 19:18:28 -080062 return DoLoadHelper(env, true, class_loader, call_res, error, error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -080063}
64
65
Alex Light7233c7e2016-07-28 10:07:45 -070066// TODO We need to acquire some locks probably.
Andreas Gampe7b38e692017-12-28 19:18:28 -080067std::unique_ptr<Agent> AgentSpec::DoLoadHelper(JNIEnv* env,
68 bool attaching,
69 jobject class_loader,
Andreas Gampeaadcbc62017-12-28 14:05:42 -080070 /*out*/jint* call_res,
71 /*out*/LoadError* error,
72 /*out*/std::string* error_msg) {
Alex Lightb284f8d2017-11-21 00:00:48 +000073 ScopedThreadStateChange stsc(Thread::Current(), ThreadState::kNative);
Alex Light7233c7e2016-07-28 10:07:45 -070074 DCHECK(call_res != nullptr);
75 DCHECK(error_msg != nullptr);
Alex Light49948e92016-08-11 15:35:28 -070076
Andreas Gampe7b38e692017-12-28 19:18:28 -080077 std::unique_ptr<Agent> agent = DoDlOpen(env, class_loader, error, error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -080078 if (agent == nullptr) {
Alex Light7233c7e2016-07-28 10:07:45 -070079 VLOG(agents) << "err: " << *error_msg;
Andreas Gampeaadcbc62017-12-28 14:05:42 -080080 return nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -070081 }
Andreas Gampeaadcbc62017-12-28 14:05:42 -080082 AgentOnLoadFunction callback = attaching ? agent->onattach_ : agent->onload_;
Leonard Mosescueb842212016-10-06 17:26:36 -070083 if (callback == nullptr) {
84 *error_msg = StringPrintf("Unable to start agent %s: No %s callback found",
85 (attaching ? "attach" : "load"),
Alex Light7233c7e2016-07-28 10:07:45 -070086 name_.c_str());
87 VLOG(agents) << "err: " << *error_msg;
Andreas Gampeaadcbc62017-12-28 14:05:42 -080088 *error = kLoadingError;
89 return nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -070090 }
Alex Light49948e92016-08-11 15:35:28 -070091 // Need to let the function fiddle with the array.
92 std::unique_ptr<char[]> copied_args(new char[args_.size() + 1]);
Andreas Gampef45d61c2017-06-07 10:29:33 -070093 strlcpy(copied_args.get(), args_.c_str(), args_.size() + 1);
Alex Light7233c7e2016-07-28 10:07:45 -070094 // TODO Need to do some checks that we are at a good spot etc.
Leonard Mosescueb842212016-10-06 17:26:36 -070095 *call_res = callback(Runtime::Current()->GetJavaVM(),
96 copied_args.get(),
97 nullptr);
Alex Light7233c7e2016-07-28 10:07:45 -070098 if (*call_res != 0) {
99 *error_msg = StringPrintf("Initialization of %s returned non-zero value of %d",
100 name_.c_str(), *call_res);
101 VLOG(agents) << "err: " << *error_msg;
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800102 *error = kInitializationError;
103 return nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -0700104 }
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800105 return agent;
Alex Light7233c7e2016-07-28 10:07:45 -0700106}
107
Andreas Gampe7b38e692017-12-28 19:18:28 -0800108std::unique_ptr<Agent> AgentSpec::DoDlOpen(JNIEnv* env,
109 jobject class_loader,
110 /*out*/LoadError* error,
111 /*out*/std::string* error_msg) {
Alex Light7233c7e2016-07-28 10:07:45 -0700112 DCHECK(error_msg != nullptr);
Leonard Mosescueb842212016-10-06 17:26:36 -0700113
Andreas Gampe7b38e692017-12-28 19:18:28 -0800114 ScopedLocalRef<jstring> library_path(env,
115 class_loader == nullptr
116 ? nullptr
117 : JavaVMExt::GetLibrarySearchPath(env, class_loader));
118
119 bool needs_native_bridge = false;
Andreas Gampe61c5e7c2018-01-18 20:34:24 -0800120 std::string nativeloader_error_msg;
Andreas Gampe7b38e692017-12-28 19:18:28 -0800121 void* dlopen_handle = android::OpenNativeLibrary(env,
122 Runtime::Current()->GetTargetSdkVersion(),
123 name_.c_str(),
124 class_loader,
125 library_path.get(),
126 &needs_native_bridge,
Andreas Gampe61c5e7c2018-01-18 20:34:24 -0800127 &nativeloader_error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800128 if (dlopen_handle == nullptr) {
Andreas Gampe61c5e7c2018-01-18 20:34:24 -0800129 *error_msg = StringPrintf("Unable to dlopen %s: %s",
130 name_.c_str(),
131 nativeloader_error_msg.c_str());
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800132 *error = kLoadingError;
133 return nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -0700134 }
Andreas Gampe7b38e692017-12-28 19:18:28 -0800135 if (needs_native_bridge) {
136 // TODO: Consider support?
137 android::CloseNativeLibrary(dlopen_handle, needs_native_bridge);
138 *error_msg = StringPrintf("Native-bridge agents unsupported: %s", name_.c_str());
139 *error = kLoadingError;
140 return nullptr;
141 }
Alex Light7233c7e2016-07-28 10:07:45 -0700142
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800143 std::unique_ptr<Agent> agent(new Agent(name_, dlopen_handle));
144 agent->PopulateFunctions();
145 *error = kNoError;
146 return agent;
147}
148
149std::ostream& operator<<(std::ostream &os, AgentSpec const& m) {
150 return os << "AgentSpec { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\" }";
151}
152
153
154void* Agent::FindSymbol(const std::string& name) const {
155 CHECK(dlopen_handle_ != nullptr) << "Cannot find symbols in an unloaded agent library " << this;
156 return dlsym(dlopen_handle_, name.c_str());
Alex Light7233c7e2016-07-28 10:07:45 -0700157}
158
159// TODO Lock some stuff probably.
160void Agent::Unload() {
161 if (dlopen_handle_ != nullptr) {
162 if (onunload_ != nullptr) {
163 onunload_(Runtime::Current()->GetJavaVM());
164 }
Andreas Gampe7b38e692017-12-28 19:18:28 -0800165 // Don't actually android::CloseNativeLibrary since some agents assume they will never get
166 // unloaded. Since this only happens when the runtime is shutting down anyway this isn't a big
167 // deal.
Alex Light7233c7e2016-07-28 10:07:45 -0700168 dlopen_handle_ = nullptr;
Leonard Mosescueb842212016-10-06 17:26:36 -0700169 onload_ = nullptr;
170 onattach_ = nullptr;
171 onunload_ = nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -0700172 } else {
173 VLOG(agents) << this << " is not currently loaded!";
174 }
175}
176
Leonard Mosescueb842212016-10-06 17:26:36 -0700177Agent::Agent(Agent&& other)
178 : dlopen_handle_(nullptr),
179 onload_(nullptr),
180 onattach_(nullptr),
181 onunload_(nullptr) {
182 *this = std::move(other);
183}
184
185Agent& Agent::operator=(Agent&& other) {
186 if (this != &other) {
187 if (dlopen_handle_ != nullptr) {
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800188 Unload();
Leonard Mosescueb842212016-10-06 17:26:36 -0700189 }
190 name_ = std::move(other.name_);
Leonard Mosescueb842212016-10-06 17:26:36 -0700191 dlopen_handle_ = other.dlopen_handle_;
192 onload_ = other.onload_;
193 onattach_ = other.onattach_;
194 onunload_ = other.onunload_;
195 other.dlopen_handle_ = nullptr;
196 other.onload_ = nullptr;
197 other.onattach_ = nullptr;
198 other.onunload_ = nullptr;
199 }
200 return *this;
201}
202
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800203void Agent::PopulateFunctions() {
204 onload_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_LOAD_FUNCTION_NAME));
205 if (onload_ == nullptr) {
206 VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this;
207 }
208 onattach_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_ATTACH_FUNCTION_NAME));
209 if (onattach_ == nullptr) {
210 VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this;
211 }
212 onunload_ = reinterpret_cast<AgentOnUnloadFunction>(FindSymbol(AGENT_ON_UNLOAD_FUNCTION_NAME));
213 if (onunload_ == nullptr) {
214 VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this;
215 }
216}
217
Alex Light7233c7e2016-07-28 10:07:45 -0700218Agent::~Agent() {
219 if (dlopen_handle_ != nullptr) {
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800220 Unload();
Alex Light7233c7e2016-07-28 10:07:45 -0700221 }
222}
223
224std::ostream& operator<<(std::ostream &os, const Agent* m) {
225 return os << *m;
226}
227
228std::ostream& operator<<(std::ostream &os, Agent const& m) {
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800229 return os << "Agent { name=\"" << m.name_ << "\", handle=" << m.dlopen_handle_ << " }";
Alex Light7233c7e2016-07-28 10:07:45 -0700230}
231
232} // namespace ti
233} // namespace art