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 #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 
     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 
     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.
     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.
     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 
    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 
    155 std::ostream& operator<<(std::ostream &os, AgentSpec const& m) {
    156   return os << "AgentSpec { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\" }";
    157 }
    158 
    159 
    160 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.
    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 
    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 
    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 
    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 
    224 Agent::~Agent() {
    225   if (dlopen_handle_ != nullptr) {
    226     Unload();
    227   }
    228 }
    229 
    230 std::ostream& operator<<(std::ostream &os, const Agent* m) {
    231   return os << *m;
    232 }
    233 
    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