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
AgentSpec(const std::string & arg)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
Load(jint * call_res,LoadError * error,std::string * error_msg)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.
Attach(JNIEnv * env,jobject class_loader,jint * call_res,LoadError * error,std::string * error_msg)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.
DoLoadHelper(JNIEnv * env,bool attaching,jobject class_loader,jint * call_res,LoadError * error,std::string * error_msg)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
DoDlOpen(JNIEnv * env,jobject class_loader,LoadError * error,std::string * error_msg)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
operator <<(std::ostream & os,AgentSpec const & m)155 std::ostream& operator<<(std::ostream &os, AgentSpec const& m) {
156 return os << "AgentSpec { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\" }";
157 }
158
159
FindSymbol(const std::string & name) const160 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.
Unload()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
Agent(Agent && other)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
operator =(Agent && other)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
PopulateFunctions()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
~Agent()224 Agent::~Agent() {
225 if (dlopen_handle_ != nullptr) {
226 Unload();
227 }
228 }
229
operator <<(std::ostream & os,const Agent * m)230 std::ostream& operator<<(std::ostream &os, const Agent* m) {
231 return os << *m;
232 }
233
operator <<(std::ostream & os,Agent const & m)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