blob: 5699c96ffc06f0763bd27f9ce083cb71c9fb9581 [file] [edit]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "DynamicInstrumentationManager.h"
#include "DebugLog.h"
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
#include <assert.h>
#include <dlfcn.h>
#include <log/log.h>
#include <optional>
#include <string>
#include <vector>
namespace android::uprobestats::dynamic_instrumentation_manager {
struct ADynamicInstrumentationManager_MethodDescriptor;
typedef struct ADynamicInstrumentationManager_MethodDescriptor
ADynamicInstrumentationManager_MethodDescriptor;
struct ADynamicInstrumentationManager_TargetProcess;
typedef struct ADynamicInstrumentationManager_TargetProcess
ADynamicInstrumentationManager_TargetProcess;
struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets;
typedef struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets
ADynamicInstrumentationManager_ExecutableMethodFileOffsets;
typedef ADynamicInstrumentationManager_TargetProcess *(
*ADynamicInstrumentationManager_TargetProcess_create)(
uid_t uid, pid_t pid, const char *processName);
typedef void (*ADynamicInstrumentationManager_TargetProcess_destroy)(
const ADynamicInstrumentationManager_TargetProcess *instance);
typedef ADynamicInstrumentationManager_MethodDescriptor *(
*ADynamicInstrumentationManager_MethodDescriptor_create)(
const char *fullyQualifiedClassName, const char *methodName,
const char *fullyQualifiedParameters[], unsigned int numParameters);
typedef void (*ADynamicInstrumentationManager_MethodDescriptor_destroy)(
const ADynamicInstrumentationManager_MethodDescriptor *instance);
typedef const char *(
*ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath)(
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance);
typedef unsigned long (
*ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset)(
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance);
typedef unsigned long (
*ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset)(
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance);
typedef void (
*ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy)(
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance);
typedef int32_t (
*ADynamicInstrumentationManager_getExecutableMethodFileOffsets)(
const ADynamicInstrumentationManager_TargetProcess &targetProcess,
const ADynamicInstrumentationManager_MethodDescriptor &methodDescriptor,
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets **out);
const char kLibandroidPath[] = "libandroid.so";
template <typename T>
void getLibFunction(void *handle, const char *identifier, T *out) {
auto result = reinterpret_cast<T>(dlsym(handle, identifier));
if (!result) {
ALOGE("dlsym error: %s %s %s", __func__, dlerror(), identifier);
assert(result);
}
*out = result;
}
std::optional<ExecutableMethodFileOffsets>
getExecutableMethodFileOffsets(std::string &processName, std::string &fqcn,
std::string &methodName,
std::vector<std::string> &fqParameters) {
void *handle = dlopen(kLibandroidPath, RTLD_NOW | RTLD_LOCAL);
if (!handle) {
ALOGE("dlopen error: %s %s", __func__, dlerror());
return {};
}
ADynamicInstrumentationManager_TargetProcess_create targetProcess_create;
getLibFunction(handle, "ADynamicInstrumentationManager_TargetProcess_create",
&targetProcess_create);
ADynamicInstrumentationManager_TargetProcess_destroy targetProcess_destroy;
getLibFunction(handle, "ADynamicInstrumentationManager_TargetProcess_destroy",
&targetProcess_destroy);
ADynamicInstrumentationManager_MethodDescriptor_create
methodDescriptor_create;
getLibFunction(handle,
"ADynamicInstrumentationManager_MethodDescriptor_create",
&methodDescriptor_create);
ADynamicInstrumentationManager_MethodDescriptor_destroy
methodDescriptor_destroy;
getLibFunction(handle,
"ADynamicInstrumentationManager_MethodDescriptor_destroy",
&methodDescriptor_destroy);
ADynamicInstrumentationManager_getExecutableMethodFileOffsets
getExecutableMethodFileOffsets;
getLibFunction(
handle, "ADynamicInstrumentationManager_getExecutableMethodFileOffsets",
&getExecutableMethodFileOffsets);
ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy
executableMethodFileOffsets_destroy;
getLibFunction(
handle,
"ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy",
&executableMethodFileOffsets_destroy);
ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath
getContainerPath;
getLibFunction(handle,
"ADynamicInstrumentationManager_ExecutableMethodFileOffsets_"
"getContainerPath",
&getContainerPath);
ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset
getContainerOffset;
getLibFunction(handle,
"ADynamicInstrumentationManager_ExecutableMethodFileOffsets_"
"getContainerOffset",
&getContainerOffset);
ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset
getMethodOffset;
getLibFunction(handle,
"ADynamicInstrumentationManager_ExecutableMethodFileOffsets_"
"getMethodOffset",
&getMethodOffset);
const ADynamicInstrumentationManager_TargetProcess *targetProcess =
targetProcess_create(0, 0, processName.c_str());
std::vector<const char *> fqpVec;
for (size_t i = 0; i < fqParameters.size(); ++i) {
fqpVec.push_back(fqParameters[i].c_str());
}
const ADynamicInstrumentationManager_MethodDescriptor *methodDescriptor =
methodDescriptor_create(fqcn.c_str(), methodName.c_str(), fqpVec.data(),
fqParameters.size());
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *offsets =
nullptr;
int32_t result = getExecutableMethodFileOffsets(*targetProcess,
*methodDescriptor, &offsets);
targetProcess_destroy(targetProcess);
methodDescriptor_destroy(methodDescriptor);
if (result != 0) {
LOG(ERROR) << "error calling getExecutableMethodFileOffsets. result: "
<< result;
}
if (offsets == nullptr) {
LOG(ERROR) << "could not find offset for " << methodName;
return {};
}
const char *cp = getContainerPath(offsets);
std::string containerPath(cp);
uint64_t containerOffset = getContainerOffset(offsets);
uint64_t methodOffset = getMethodOffset(offsets);
executableMethodFileOffsets_destroy(offsets);
ExecutableMethodFileOffsets executableMethodFileOffsets;
executableMethodFileOffsets.containerPath = containerPath;
executableMethodFileOffsets.containerOffset = containerOffset;
executableMethodFileOffsets.methodOffset = methodOffset;
return executableMethodFileOffsets;
}
} // namespace android::uprobestats::dynamic_instrumentation_manager