1 // Copyright 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <android/binder_status.h>
16 #include <assert.h>
17 #include <dlfcn.h>
18 #include <jni.h>
19 #include <log/log.h>
20
21 #include <optional>
22 #include <stdexcept>
23 #include <string>
24 #include <vector>
25
26 #include "nativehelper/scoped_local_ref.h"
27 #include "nativehelper/scoped_utf_chars.h"
28 #include "nativehelper/utils.h"
29
30 const char kLibandroidPath[] = "libandroid.so";
31
32 struct ADynamicInstrumentationManager_MethodDescriptor;
33 typedef struct ADynamicInstrumentationManager_MethodDescriptor
34 ADynamicInstrumentationManager_MethodDescriptor;
35
36 struct ADynamicInstrumentationManager_TargetProcess;
37 typedef struct ADynamicInstrumentationManager_TargetProcess
38 ADynamicInstrumentationManager_TargetProcess;
39
40 struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets;
41 typedef struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets
42 ADynamicInstrumentationManager_ExecutableMethodFileOffsets;
43
44 typedef ADynamicInstrumentationManager_TargetProcess* (
45 *ADynamicInstrumentationManager_TargetProcess_create)(uid_t uid, pid_t pid,
46 const char* processName);
47 typedef void (*ADynamicInstrumentationManager_TargetProcess_destroy)(
48 const ADynamicInstrumentationManager_TargetProcess* instance);
49
50 typedef ADynamicInstrumentationManager_MethodDescriptor* (
51 *ADynamicInstrumentationManager_MethodDescriptor_create)(
52 const char* fullyQualifiedClassName, const char* methodName,
53 const char* fullyQualifiedParameters[], unsigned int numParameters);
54 typedef void (*ADynamicInstrumentationManager_MethodDescriptor_destroy)(
55 const ADynamicInstrumentationManager_MethodDescriptor* instance);
56
57 typedef const char* (*ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath)(
58 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance);
59 typedef unsigned long (
60 *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset)(
61 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance);
62 typedef unsigned long (*ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset)(
63 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance);
64 typedef void (*ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy)(
65 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance);
66
67 typedef binder_status_t (*ADynamicInstrumentationManager_getExecutableMethodFileOffsets)(
68 const ADynamicInstrumentationManager_TargetProcess& targetProcess,
69 const ADynamicInstrumentationManager_MethodDescriptor& methodDescriptor,
70 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets** out);
71
72 template <typename T>
getLibFunction(void * handle,const char * identifier,T * out)73 void getLibFunction(void* handle, const char* identifier, T* out) {
74 auto result = reinterpret_cast<T>(dlsym(handle, identifier));
75 if (!result) {
76 ALOGE("dlsym error: %s %s %s", __func__, dlerror(), identifier);
77 assert(result);
78 }
79 *out = result;
80 }
81
82 extern "C" jobject
Java_android_os_instrumentation_cts_DynamicInstrumentationManagerTest_getExecutableMethodFileOffsetsNative(JNIEnv * env,jclass,jint uid,jint pid,jstring processName,jstring fqcn,jstring methodName,jobjectArray fqParameters)83 Java_android_os_instrumentation_cts_DynamicInstrumentationManagerTest_getExecutableMethodFileOffsetsNative(
84 JNIEnv* env, jclass, jint uid, jint pid, jstring processName, jstring fqcn,
85 jstring methodName, jobjectArray fqParameters) {
86 void* handle = dlopen(kLibandroidPath, RTLD_NOW | RTLD_LOCAL);
87 if (!handle) {
88 ALOGE("dlopen error: %s %s", __func__, dlerror());
89 return nullptr;
90 }
91
92 ADynamicInstrumentationManager_TargetProcess_create targetProcess_create;
93 getLibFunction(handle, "ADynamicInstrumentationManager_TargetProcess_create",
94 &targetProcess_create);
95 ADynamicInstrumentationManager_TargetProcess_destroy targetProcess_destroy;
96 getLibFunction(handle, "ADynamicInstrumentationManager_TargetProcess_destroy",
97 &targetProcess_destroy);
98 ADynamicInstrumentationManager_MethodDescriptor_create methodDescriptor_create;
99 getLibFunction(handle, "ADynamicInstrumentationManager_MethodDescriptor_create",
100 &methodDescriptor_create);
101 ADynamicInstrumentationManager_MethodDescriptor_destroy methodDescriptor_destroy;
102 getLibFunction(handle, "ADynamicInstrumentationManager_MethodDescriptor_destroy",
103 &methodDescriptor_destroy);
104 ADynamicInstrumentationManager_getExecutableMethodFileOffsets getExecutableMethodFileOffsets;
105 getLibFunction(handle, "ADynamicInstrumentationManager_getExecutableMethodFileOffsets",
106 &getExecutableMethodFileOffsets);
107 ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy
108 executableMethodFileOffsets_destroy;
109 getLibFunction(handle, "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy",
110 &executableMethodFileOffsets_destroy);
111 ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath getContainerPath;
112 getLibFunction(handle,
113 "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath",
114 &getContainerPath);
115 ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset
116 getContainerOffset;
117 getLibFunction(handle,
118 "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset",
119 &getContainerOffset);
120 ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset getMethodOffset;
121 getLibFunction(handle,
122 "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset",
123 &getMethodOffset);
124
125 jsize numParams = env->GetArrayLength(fqParameters);
126 // need to hold the `ScopedUtfChars` outside the loop, so they don't get dropped too early
127 std::vector<ScopedUtfChars> scopedParams;
128 std::vector<const char*> cParams;
129 for (jsize i = 0; i < numParams; i++) {
130 ScopedLocalRef<jobject> obj(env, env->GetObjectArrayElement(fqParameters, i));
131 scopedParams.push_back(GET_UTF_OR_RETURN(env, static_cast<jstring>(obj.get())));
132 cParams.push_back(scopedParams[i].c_str());
133 }
134
135 ScopedUtfChars cProcessName = GET_UTF_OR_RETURN(env, processName);
136 ScopedUtfChars cFqcn = GET_UTF_OR_RETURN(env, fqcn);
137 ScopedUtfChars cMethodName = GET_UTF_OR_RETURN(env, methodName);
138 const ADynamicInstrumentationManager_TargetProcess* targetProcess =
139 targetProcess_create((uid_t)uid, (pid_t)pid, cProcessName.c_str());
140 const ADynamicInstrumentationManager_MethodDescriptor* methodDescriptor =
141 methodDescriptor_create(cFqcn.c_str(), cMethodName.c_str(), cParams.data(), numParams);
142
143 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* offsets = nullptr;
144 int32_t result = getExecutableMethodFileOffsets(*targetProcess, *methodDescriptor, &offsets);
145
146 targetProcess_destroy(targetProcess);
147 methodDescriptor_destroy(methodDescriptor);
148
149 ScopedLocalRef<jobject> innerClass(env, nullptr);
150 if (offsets != nullptr) {
151 ScopedLocalRef<jstring> containerPath =
152 CREATE_UTF_OR_RETURN(env, getContainerPath(offsets));
153 jlong containerOffset = static_cast<jlong>(getContainerOffset(offsets));
154 jlong methodOffset = static_cast<jlong>(getMethodOffset(offsets));
155 executableMethodFileOffsets_destroy(offsets);
156 ScopedLocalRef<jclass>
157 clazz(env,
158 env->FindClass(
159 "android/os/instrumentation/cts/"
160 "DynamicInstrumentationManagerTest$ExecutableMethodFileOffsets"));
161 if (clazz.get() == nullptr) {
162 ALOGE("Could not find JNI test class "
163 "DynamicInstrumentationManagerTest$ExecutableMethodFileOffsets");
164 return nullptr;
165 }
166 jmethodID constructor_id =
167 env->GetMethodID(clazz.get(), "<init>", "(Ljava/lang/String;JJ)V");
168 innerClass.reset(env->NewObject(clazz.get(), constructor_id, containerPath.get(),
169 containerOffset, methodOffset));
170 }
171
172 ScopedLocalRef<jclass>
173 clazz(env,
174 env->FindClass("android/os/instrumentation/cts/"
175 "DynamicInstrumentationManagerTest$OffsetsWithStatusCode"));
176 if (clazz.get() == nullptr) {
177 ALOGE("Could not find JNI test class "
178 "DynamicInstrumentationManagerTest$OffsetsWithStatusCode");
179 return nullptr;
180 }
181
182 jmethodID constructor_id =
183 env->GetMethodID(clazz.get(), "<init>",
184 "(ILandroid/os/instrumentation/cts/"
185 "DynamicInstrumentationManagerTest$ExecutableMethodFileOffsets;)V");
186 return env->NewObject(clazz.get(), constructor_id, result, innerClass.get());
187 }
188