xref: /aosp_15_r20/cts/tests/tests/uprobestats/jni/test_dynamic_instrumentation_manager.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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