summaryrefslogtreecommitdiff
path: root/core/jni/android
diff options
context:
space:
mode:
authorStan Iliev <stani@google.com>2020-02-03 16:57:09 -0500
committerStan Iliev <stani@google.com>2020-02-07 12:27:07 -0500
commitc90438175fcd83c8890c426c28a3ded006faee35 (patch)
tree858217b23a153fbb64b3493d552ee09486b75777 /core/jni/android
parent76d19db2e4650ca4046056019b7e9db557a17b06 (diff)
Refactor GraphicsStatsService for updateability
Move GraphicsStatsService to android.graphics package. Move GraphicsStatsService JNI from libservices.core to libandroid_runtime. Declare GraphicsStatsService ctor as the only @SystemApi. Remove MemoryFile usage from GraphicsStatsService, but use SharedMemory and other SDK APIs instead. This is done to avoid using unstable API MemoryFile.getFileDescriptor. Propose new SharedMemory.getFdDup API for next release, which is hidden for now. Refactor statsd puller to avoid proto serialization by moving data directly into AStatsEventList. "libprotoutil" is added as a static dependancy to libhwui, which should be fine because its implementation does not link anything. Bug: 146353313 Test: Ran "adb shell cmd stats pull-source 10068" Test: Passed unit tests and GraphicsStatsValidationTest CTS Change-Id: If16c5addbd519cba33e03bd84ac312595032e0e1
Diffstat (limited to 'core/jni/android')
-rw-r--r--core/jni/android/graphics/GraphicsStatsService.cpp195
1 files changed, 195 insertions, 0 deletions
diff --git a/core/jni/android/graphics/GraphicsStatsService.cpp b/core/jni/android/graphics/GraphicsStatsService.cpp
new file mode 100644
index 000000000000..ef0aacc4d9ec
--- /dev/null
+++ b/core/jni/android/graphics/GraphicsStatsService.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "GraphicsStatsService"
+
+#include <JankTracker.h>
+#include <jni.h>
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <service/GraphicsStatsService.h>
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+#include <statslog.h>
+#include "core_jni_helpers.h"
+
+namespace android {
+
+using namespace android::uirenderer;
+
+static jint getAshmemSize(JNIEnv*, jobject) {
+ return sizeof(ProfileData);
+}
+
+static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) {
+ GraphicsStatsService::Dump* dump =
+ GraphicsStatsService::createDump(fd,
+ isProto ? GraphicsStatsService::DumpType::Protobuf
+ : GraphicsStatsService::DumpType::Text);
+ return reinterpret_cast<jlong>(dump);
+}
+
+static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
+ jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+ std::string path;
+ const ProfileData* data = nullptr;
+ LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
+ ScopedByteArrayRO buffer{env};
+ if (jdata != nullptr) {
+ buffer.reset(jdata);
+ LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
+ "Buffer size %zu doesn't match expected %zu!", buffer.size(),
+ sizeof(ProfileData));
+ data = reinterpret_cast<const ProfileData*>(buffer.get());
+ }
+ if (jpath != nullptr) {
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(),
+ "Failed to get path chars");
+ path.assign(pathChars.c_str(), pathChars.size());
+ }
+ ScopedUtfChars packageChars(env, jpackage);
+ LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
+ "Failed to get path chars");
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
+
+ const std::string package(packageChars.c_str(), packageChars.size());
+ GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
+}
+
+static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
+ const std::string path(pathChars.c_str(), pathChars.size());
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ GraphicsStatsService::addToDump(dump, path);
+}
+
+static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ GraphicsStatsService::finishDump(dump);
+}
+
+static void finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr, jlong pulledData,
+ jboolean lastFullDay) {
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ AStatsEventList* data = reinterpret_cast<AStatsEventList*>(pulledData);
+ GraphicsStatsService::finishDumpInMemory(dump, data, lastFullDay == JNI_TRUE);
+}
+
+static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
+ jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+ ScopedByteArrayRO buffer(env, jdata);
+ LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
+ "Buffer size %zu doesn't match expected %zu!", buffer.size(),
+ sizeof(ProfileData));
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
+ ScopedUtfChars packageChars(env, jpackage);
+ LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
+ "Failed to get path chars");
+
+ const std::string path(pathChars.c_str(), pathChars.size());
+ const std::string package(packageChars.c_str(), packageChars.size());
+ const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get());
+ GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data);
+}
+
+static jobject gGraphicsStatsServiceObject = nullptr;
+static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
+
+static JNIEnv* getJNIEnv() {
+ JavaVM* vm = AndroidRuntime::getJavaVM();
+ JNIEnv* env = nullptr;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+ }
+ }
+ return env;
+}
+
+// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom.
+static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag,
+ AStatsEventList* data,
+ void* cookie) {
+ JNIEnv* env = getJNIEnv();
+ if (!env) {
+ return false;
+ }
+ if (gGraphicsStatsServiceObject == nullptr) {
+ ALOGE("Failed to get graphicsstats service");
+ return AStatsManager_PULL_SKIP;
+ }
+
+ for (bool lastFullDay : {true, false}) {
+ env->CallVoidMethod(gGraphicsStatsServiceObject,
+ gGraphicsStatsService_pullGraphicsStatsMethodID,
+ (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE),
+ reinterpret_cast<jlong>(data));
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ ALOGE("Failed to invoke graphicsstats service");
+ return AStatsManager_PULL_SKIP;
+ }
+ }
+ return AStatsManager_PULL_SUCCESS;
+}
+
+// Register a puller for GRAPHICS_STATS atom with the statsd service.
+static void nativeInit(JNIEnv* env, jobject javaObject) {
+ gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject);
+ AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+ AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds
+ AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds
+
+ AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS,
+ &graphicsStatsPullCallback, metadata, nullptr);
+
+ AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+static void nativeDestructor(JNIEnv* env, jobject javaObject) {
+ AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS);
+ env->DeleteGlobalRef(gGraphicsStatsServiceObject);
+ gGraphicsStatsServiceObject = nullptr;
+}
+
+static const JNINativeMethod sMethods[] =
+ {{"nGetAshmemSize", "()I", (void*)getAshmemSize},
+ {"nCreateDump", "(IZ)J", (void*)createDump},
+ {"nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)addToDump},
+ {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump},
+ {"nFinishDump", "(J)V", (void*)finishDump},
+ {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory},
+ {"nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)saveBuffer},
+ {"nativeInit", "()V", (void*)nativeInit},
+ {"nativeDestructor", "()V", (void*)nativeDestructor}};
+
+int register_android_graphics_GraphicsStatsService(JNIEnv* env) {
+ jclass graphicsStatsService_class =
+ FindClassOrDie(env, "android/graphics/GraphicsStatsService");
+ gGraphicsStatsService_pullGraphicsStatsMethodID =
+ GetMethodIDOrDie(env, graphicsStatsService_class, "pullGraphicsStats", "(ZJ)V");
+ return jniRegisterNativeMethods(env, "android/graphics/GraphicsStatsService", sMethods,
+ NELEM(sMethods));
+}
+
+} // namespace android