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