/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include"PowerCounters.h" #include"nsXULAppAPI.h"// for XRE_IsParentProcess #include <dlfcn.h>
/** Used by `ANDROID_DLEXT_RESERVED_ADDRESS` and
* `ANDROID_DLEXT_RESERVED_ADDRESS_HINT`. */ void* _Nullable reserved_addr; /** Used by `ANDROID_DLEXT_RESERVED_ADDRESS` and
* `ANDROID_DLEXT_RESERVED_ADDRESS_HINT`. */
size_t reserved_size;
/** Used by `ANDROID_DLEXT_WRITE_RELRO` and `ANDROID_DLEXT_USE_RELRO`. */ int relro_fd;
/** Used by `ANDROID_DLEXT_USE_LIBRARY_FD`. */ int library_fd; /** Used by `ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET` */
off64_t library_fd_offset;
PowerCounters::PowerCounters() { if (!XRE_IsParentProcess()) { // Energy meters are global, so only sample them on the parent. return;
}
// A direct dlopen call on libperfetto_android_internal.so fails with a // namespace error because libperfetto_android_internal.so is missing in // /etc/public.libraries.txt // Instead, use android_dlopen_ext with the "default" namespace. void* libcHandle = dlopen("libc.so", RTLD_LAZY); if (!libcHandle) {
ALOG("failed to dlopen libc: %s", dlerror()); return;
}
struct android_namespace_t* (*android_get_exported_namespace)(constchar*) = reinterpret_cast<struct android_namespace_t* (*)(constchar*)>(
dlsym(libcHandle, "__loader_android_get_exported_namespace")); if (!android_get_exported_namespace) {
ALOG("failed to get __loader_android_get_exported_namespace: %s",
dlerror()); return;
}
mLibperfettoModule = android_dlopen_ext("libperfetto_android_internal.so",
RTLD_LOCAL | RTLD_LAZY, &dlextinfo);
MOZ_ASSERT(mLibperfettoModule); if (!mLibperfettoModule) {
ALOG("failed to get libperfetto handle: %s", dlerror()); return;
}
decltype(&GetAvailableRails) getAvailableRails = reinterpret_cast<decltype(&GetAvailableRails)>(
dlsym(mLibperfettoModule, "GetAvailableRails")); if (!getAvailableRails) {
ALOG("failed to get GetAvailableRails pointer: %s", dlerror()); return;
}
constexpr size_t kMaxNumRails = 32; if (!mRailDescriptors.resize(kMaxNumRails)) {
ALOG("failed to grow mRailDescriptors"); return;
}
size_t numRails = mRailDescriptors.length();
getAvailableRails(&mRailDescriptors[0], &numRails);
mRailDescriptors.shrinkTo(numRails);
ALOG("found %zu rails", numRails); if (numRails == 0) { // We will see 0 rails either if the device has no support for power // profiling or if the SELinux policy blocks access (ie. on a non-rooted // device). return;
}
if (!mRailEnergyData.resize(numRails)) {
ALOG("failed to grow mRailEnergyData"); return;
} for (size_t i = 0; i < numRails; ++i) {
RailDescriptor& rail = mRailDescriptors[i];
ALOG("rail %zu, name: %s, subsystem: %s", i, rail.rail_name,
rail.subsys_name);
RailEnergy* railEnergy = new RailEnergy(&mRailEnergyData[i], rail.rail_name, rail.subsys_name); if (!mCounters.emplaceBack(railEnergy)) { delete railEnergy;
}
}
mGetRailEnergyData = reinterpret_cast<decltype(&GetRailEnergyData)>(
dlsym(mLibperfettoModule, "GetRailEnergyData")); if (!mGetRailEnergyData) {
ALOG("failed to get GetRailEnergyData pointer"); return;
}
}
PowerCounters::~PowerCounters() { if (mLibperfettoModule) {
dlclose(mLibperfettoModule);
}
} void PowerCounters::Sample() { // Energy meters are global, so only sample them on the parent. // Also return early if we failed to access the GetRailEnergyData symbol. if (!XRE_IsParentProcess() || !mGetRailEnergyData) { return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.