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