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