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 #ifndef ART_RUNTIME_TI_AGENT_H_
18 #define ART_RUNTIME_TI_AGENT_H_
19 
20 #include <dlfcn.h>
21 #include <jni.h>  // for jint, JavaVM* etc declarations
22 
23 #include "runtime.h"
24 #include "utils.h"
25 
26 namespace art {
27 namespace ti {
28 
29 using AgentOnLoadFunction = jint (*)(JavaVM*, const char*, void*);
30 using AgentOnUnloadFunction = void (*)(JavaVM*);
31 
32 // Agents are native libraries that will be loaded by the runtime for the purpose of
33 // instrumentation. They will be entered by Agent_OnLoad or Agent_OnAttach depending on whether the
34 // agent is being attached during runtime startup or later.
35 //
36 // The agent's Agent_OnUnload function will be called during runtime shutdown.
37 //
38 // TODO: consider splitting ti::Agent into command line, agent and shared library handler classes
39 // TODO Support native-bridge. Currently agents can only be the actual runtime ISA of the device.
40 class Agent {
41  public:
42   enum LoadError {
43     kNoError,              // No error occurred..
44     kAlreadyStarted,       // The agent has already been loaded.
45     kLoadingError,         // dlopen or dlsym returned an error.
46     kInitializationError,  // The entrypoint did not return 0. This might require an abort.
47   };
48 
IsStarted()49   bool IsStarted() const {
50     return dlopen_handle_ != nullptr;
51   }
52 
GetName()53   const std::string& GetName() const {
54     return name_;
55   }
56 
GetArgs()57   const std::string& GetArgs() const {
58     return args_;
59   }
60 
HasArgs()61   bool HasArgs() const {
62     return !GetArgs().empty();
63   }
64 
65   void* FindSymbol(const std::string& name) const;
66 
Load(jint * call_res,std::string * error_msg)67   LoadError Load(/*out*/jint* call_res, /*out*/std::string* error_msg) {
68     VLOG(agents) << "Loading agent: " << name_ << " " << args_;
69     return DoLoadHelper(false, call_res, error_msg);
70   }
71 
72   // TODO We need to acquire some locks probably.
73   void Unload();
74 
75   // Tries to attach the agent using its OnAttach method. Returns true on success.
Attach(jint * call_res,std::string * error_msg)76   LoadError Attach(/*out*/jint* call_res, /*out*/std::string* error_msg) {
77     VLOG(agents) << "Attaching agent: " << name_ << " " << args_;
78     return DoLoadHelper(true, call_res, error_msg);
79   }
80 
81   explicit Agent(std::string arg);
82 
83   Agent(const Agent& other);
84   Agent& operator=(const Agent& other);
85 
86   Agent(Agent&& other);
87   Agent& operator=(Agent&& other);
88 
89   ~Agent();
90 
91  private:
92   LoadError DoDlOpen(/*out*/std::string* error_msg);
93 
94   LoadError DoLoadHelper(bool attaching,
95                          /*out*/jint* call_res,
96                          /*out*/std::string* error_msg);
97 
98   std::string name_;
99   std::string args_;
100   void* dlopen_handle_;
101 
102   // The entrypoints.
103   AgentOnLoadFunction onload_;
104   AgentOnLoadFunction onattach_;
105   AgentOnUnloadFunction onunload_;
106 
107   friend std::ostream& operator<<(std::ostream &os, Agent const& m);
108 };
109 
110 std::ostream& operator<<(std::ostream &os, Agent const& m);
111 std::ostream& operator<<(std::ostream &os, const Agent* m);
112 
113 }  // namespace ti
114 }  // namespace art
115 
116 #endif  // ART_RUNTIME_TI_AGENT_H_
117 
118