blob: cdfe727e50183d351378c025acc4ad66291ef842 [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 Gampe85f1c572018-11-21 13:52:48 -080023#include "base/logging.h"
Andreas Gampef45d61c2017-06-07 10:29:33 -070024#include "base/strlcpy.h"
Vladimir Markoa3ad0cd2018-05-04 10:06:38 +010025#include "jni/java_vm_ext.h"
Alex Light7233c7e2016-07-28 10:07:45 -070026#include "runtime.h"
Alex Lightb284f8d2017-11-21 00:00:48 +000027#include "thread-current-inl.h"
28#include "scoped_thread_state_change-inl.h"
Alex Light7233c7e2016-07-28 10:07:45 -070029
30namespace art {
31namespace ti {
32
Andreas Gampe46ee31b2016-12-14 10:11:49 -080033using android::base::StringPrintf;
34
Alex Light7233c7e2016-07-28 10:07:45 -070035const char* AGENT_ON_LOAD_FUNCTION_NAME = "Agent_OnLoad";
36const char* AGENT_ON_ATTACH_FUNCTION_NAME = "Agent_OnAttach";
37const char* AGENT_ON_UNLOAD_FUNCTION_NAME = "Agent_OnUnload";
38
Andreas Gampeaadcbc62017-12-28 14:05:42 -080039AgentSpec::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
49std::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_;
Andreas Gampe7b38e692017-12-28 19:18:28 -080053 return DoLoadHelper(nullptr, false, nullptr, call_res, error, error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -080054}
55
56// Tries to attach the agent using its OnAttach method. Returns true on success.
Andreas Gampe7b38e692017-12-28 19:18:28 -080057std::unique_ptr<Agent> AgentSpec::Attach(JNIEnv* env,
58 jobject class_loader,
59 /*out*/jint* call_res,
Andreas Gampeaadcbc62017-12-28 14:05:42 -080060 /*out*/LoadError* error,
61 /*out*/std::string* error_msg) {
62 VLOG(agents) << "Attaching agent: " << name_ << " " << args_;
Andreas Gampe7b38e692017-12-28 19:18:28 -080063 return DoLoadHelper(env, true, class_loader, call_res, error, error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -080064}
65
66
Alex Light7233c7e2016-07-28 10:07:45 -070067// TODO We need to acquire some locks probably.
Andreas Gampe7b38e692017-12-28 19:18:28 -080068std::unique_ptr<Agent> AgentSpec::DoLoadHelper(JNIEnv* env,
69 bool attaching,
70 jobject class_loader,
Andreas Gampeaadcbc62017-12-28 14:05:42 -080071 /*out*/jint* call_res,
72 /*out*/LoadError* error,
73 /*out*/std::string* error_msg) {
Alex Lightb284f8d2017-11-21 00:00:48 +000074 ScopedThreadStateChange stsc(Thread::Current(), ThreadState::kNative);
Alex Light7233c7e2016-07-28 10:07:45 -070075 DCHECK(call_res != nullptr);
76 DCHECK(error_msg != nullptr);
Alex Light49948e92016-08-11 15:35:28 -070077
Andreas Gampe7b38e692017-12-28 19:18:28 -080078 std::unique_ptr<Agent> agent = DoDlOpen(env, class_loader, error, error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -080079 if (agent == nullptr) {
Alex Light7233c7e2016-07-28 10:07:45 -070080 VLOG(agents) << "err: " << *error_msg;
Andreas Gampeaadcbc62017-12-28 14:05:42 -080081 return nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -070082 }
Andreas Gampeaadcbc62017-12-28 14:05:42 -080083 AgentOnLoadFunction callback = attaching ? agent->onattach_ : agent->onload_;
Leonard Mosescueb842212016-10-06 17:26:36 -070084 if (callback == nullptr) {
85 *error_msg = StringPrintf("Unable to start agent %s: No %s callback found",
86 (attaching ? "attach" : "load"),
Alex Light7233c7e2016-07-28 10:07:45 -070087 name_.c_str());
88 VLOG(agents) << "err: " << *error_msg;
Andreas Gampeaadcbc62017-12-28 14:05:42 -080089 *error = kLoadingError;
90 return nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -070091 }
Alex Light49948e92016-08-11 15:35:28 -070092 // Need to let the function fiddle with the array.
93 std::unique_ptr<char[]> copied_args(new char[args_.size() + 1]);
Andreas Gampef45d61c2017-06-07 10:29:33 -070094 strlcpy(copied_args.get(), args_.c_str(), args_.size() + 1);
Alex Light7233c7e2016-07-28 10:07:45 -070095 // TODO Need to do some checks that we are at a good spot etc.
Leonard Mosescueb842212016-10-06 17:26:36 -070096 *call_res = callback(Runtime::Current()->GetJavaVM(),
97 copied_args.get(),
98 nullptr);
Alex Light7233c7e2016-07-28 10:07:45 -070099 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;
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800103 *error = kInitializationError;
104 return nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -0700105 }
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800106 return agent;
Alex Light7233c7e2016-07-28 10:07:45 -0700107}
108
Andreas Gampe7b38e692017-12-28 19:18:28 -0800109std::unique_ptr<Agent> AgentSpec::DoDlOpen(JNIEnv* env,
110 jobject class_loader,
111 /*out*/LoadError* error,
112 /*out*/std::string* error_msg) {
Alex Light7233c7e2016-07-28 10:07:45 -0700113 DCHECK(error_msg != nullptr);
Leonard Mosescueb842212016-10-06 17:26:36 -0700114
Andreas Gampe7b38e692017-12-28 19:18:28 -0800115 ScopedLocalRef<jstring> library_path(env,
116 class_loader == nullptr
117 ? nullptr
118 : JavaVMExt::GetLibrarySearchPath(env, class_loader));
119
120 bool needs_native_bridge = false;
Nicolas Geoffrayd9b30692019-01-12 14:59:05 +0000121 char* nativeloader_error_msg = nullptr;
Andreas Gampe7b38e692017-12-28 19:18:28 -0800122 void* dlopen_handle = android::OpenNativeLibrary(env,
123 Runtime::Current()->GetTargetSdkVersion(),
124 name_.c_str(),
125 class_loader,
Nicolas Geoffray96259f12019-01-18 10:04:51 +0000126 nullptr,
Andreas Gampe7b38e692017-12-28 19:18:28 -0800127 library_path.get(),
128 &needs_native_bridge,
Andreas Gampe61c5e7c2018-01-18 20:34:24 -0800129 &nativeloader_error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800130 if (dlopen_handle == nullptr) {
Andreas Gampe61c5e7c2018-01-18 20:34:24 -0800131 *error_msg = StringPrintf("Unable to dlopen %s: %s",
132 name_.c_str(),
Nicolas Geoffrayd9b30692019-01-12 14:59:05 +0000133 nativeloader_error_msg);
134 android::NativeLoaderFreeErrorMessage(nativeloader_error_msg);
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800135 *error = kLoadingError;
136 return nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -0700137 }
Andreas Gampe7b38e692017-12-28 19:18:28 -0800138 if (needs_native_bridge) {
139 // TODO: Consider support?
dimitry947573e2018-09-12 01:12:56 +0200140 // The result of this call and error_msg is ignored because the most
141 // relevant error is that native bridge is unsupported.
Nicolas Geoffrayd9b30692019-01-12 14:59:05 +0000142 android::CloseNativeLibrary(dlopen_handle, needs_native_bridge, &nativeloader_error_msg);
Nicolas Geoffray75c513a2019-01-18 08:39:27 +0000143 android::NativeLoaderFreeErrorMessage(nativeloader_error_msg);
Andreas Gampe7b38e692017-12-28 19:18:28 -0800144 *error_msg = StringPrintf("Native-bridge agents unsupported: %s", name_.c_str());
145 *error = kLoadingError;
146 return nullptr;
147 }
Alex Light7233c7e2016-07-28 10:07:45 -0700148
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800149 std::unique_ptr<Agent> agent(new Agent(name_, dlopen_handle));
150 agent->PopulateFunctions();
151 *error = kNoError;
152 return agent;
153}
154
155std::ostream& operator<<(std::ostream &os, AgentSpec const& m) {
156 return os << "AgentSpec { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\" }";
157}
158
159
160void* 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());
Alex Light7233c7e2016-07-28 10:07:45 -0700163}
164
165// TODO Lock some stuff probably.
166void Agent::Unload() {
167 if (dlopen_handle_ != nullptr) {
168 if (onunload_ != nullptr) {
169 onunload_(Runtime::Current()->GetJavaVM());
170 }
Andreas Gampe7b38e692017-12-28 19:18:28 -0800171 // 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.
Alex Light7233c7e2016-07-28 10:07:45 -0700174 dlopen_handle_ = nullptr;
Leonard Mosescueb842212016-10-06 17:26:36 -0700175 onload_ = nullptr;
176 onattach_ = nullptr;
177 onunload_ = nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -0700178 } else {
179 VLOG(agents) << this << " is not currently loaded!";
180 }
181}
182
Andreas Gampe44b31742018-10-01 19:30:57 -0700183Agent::Agent(Agent&& other) noexcept
Leonard Mosescueb842212016-10-06 17:26:36 -0700184 : dlopen_handle_(nullptr),
185 onload_(nullptr),
186 onattach_(nullptr),
187 onunload_(nullptr) {
188 *this = std::move(other);
189}
190
Andreas Gampe44b31742018-10-01 19:30:57 -0700191Agent& Agent::operator=(Agent&& other) noexcept {
Leonard Mosescueb842212016-10-06 17:26:36 -0700192 if (this != &other) {
193 if (dlopen_handle_ != nullptr) {
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800194 Unload();
Leonard Mosescueb842212016-10-06 17:26:36 -0700195 }
196 name_ = std::move(other.name_);
Leonard Mosescueb842212016-10-06 17:26:36 -0700197 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
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800209void 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
Alex Light7233c7e2016-07-28 10:07:45 -0700224Agent::~Agent() {
225 if (dlopen_handle_ != nullptr) {
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800226 Unload();
Alex Light7233c7e2016-07-28 10:07:45 -0700227 }
228}
229
230std::ostream& operator<<(std::ostream &os, const Agent* m) {
231 return os << *m;
232}
233
234std::ostream& operator<<(std::ostream &os, Agent const& m) {
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800235 return os << "Agent { name=\"" << m.name_ << "\", handle=" << m.dlopen_handle_ << " }";
Alex Light7233c7e2016-07-28 10:07:45 -0700236}
237
238} // namespace ti
239} // namespace art