blob: ef0aacc4d9eca140436e543b277cbb35cdb5d549 [file] [log] [blame]
Stan Ilievc9043812020-02-03 16:57:09 -05001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "GraphicsStatsService"
18
19#include <JankTracker.h>
20#include <jni.h>
21#include <log/log.h>
22#include <nativehelper/JNIHelp.h>
23#include <nativehelper/ScopedPrimitiveArray.h>
24#include <nativehelper/ScopedUtfChars.h>
25#include <service/GraphicsStatsService.h>
26#include <stats_event.h>
27#include <stats_pull_atom_callback.h>
28#include <statslog.h>
29#include "core_jni_helpers.h"
30
31namespace android {
32
33using namespace android::uirenderer;
34
35static jint getAshmemSize(JNIEnv*, jobject) {
36 return sizeof(ProfileData);
37}
38
39static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) {
40 GraphicsStatsService::Dump* dump =
41 GraphicsStatsService::createDump(fd,
42 isProto ? GraphicsStatsService::DumpType::Protobuf
43 : GraphicsStatsService::DumpType::Text);
44 return reinterpret_cast<jlong>(dump);
45}
46
47static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
48 jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
49 std::string path;
50 const ProfileData* data = nullptr;
51 LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
52 ScopedByteArrayRO buffer{env};
53 if (jdata != nullptr) {
54 buffer.reset(jdata);
55 LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
56 "Buffer size %zu doesn't match expected %zu!", buffer.size(),
57 sizeof(ProfileData));
58 data = reinterpret_cast<const ProfileData*>(buffer.get());
59 }
60 if (jpath != nullptr) {
61 ScopedUtfChars pathChars(env, jpath);
62 LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(),
63 "Failed to get path chars");
64 path.assign(pathChars.c_str(), pathChars.size());
65 }
66 ScopedUtfChars packageChars(env, jpackage);
67 LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
68 "Failed to get path chars");
69 GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
70 LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
71
72 const std::string package(packageChars.c_str(), packageChars.size());
73 GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
74}
75
76static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
77 ScopedUtfChars pathChars(env, jpath);
78 LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
79 const std::string path(pathChars.c_str(), pathChars.size());
80 GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
81 GraphicsStatsService::addToDump(dump, path);
82}
83
84static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
85 GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
86 GraphicsStatsService::finishDump(dump);
87}
88
89static void finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr, jlong pulledData,
90 jboolean lastFullDay) {
91 GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
92 AStatsEventList* data = reinterpret_cast<AStatsEventList*>(pulledData);
93 GraphicsStatsService::finishDumpInMemory(dump, data, lastFullDay == JNI_TRUE);
94}
95
96static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
97 jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
98 ScopedByteArrayRO buffer(env, jdata);
99 LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
100 "Buffer size %zu doesn't match expected %zu!", buffer.size(),
101 sizeof(ProfileData));
102 ScopedUtfChars pathChars(env, jpath);
103 LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
104 ScopedUtfChars packageChars(env, jpackage);
105 LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
106 "Failed to get path chars");
107
108 const std::string path(pathChars.c_str(), pathChars.size());
109 const std::string package(packageChars.c_str(), packageChars.size());
110 const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get());
111 GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data);
112}
113
114static jobject gGraphicsStatsServiceObject = nullptr;
115static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
116
117static JNIEnv* getJNIEnv() {
118 JavaVM* vm = AndroidRuntime::getJavaVM();
119 JNIEnv* env = nullptr;
120 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
121 if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
122 LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
123 }
124 }
125 return env;
126}
127
128// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom.
129static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag,
130 AStatsEventList* data,
131 void* cookie) {
132 JNIEnv* env = getJNIEnv();
133 if (!env) {
134 return false;
135 }
136 if (gGraphicsStatsServiceObject == nullptr) {
137 ALOGE("Failed to get graphicsstats service");
138 return AStatsManager_PULL_SKIP;
139 }
140
141 for (bool lastFullDay : {true, false}) {
142 env->CallVoidMethod(gGraphicsStatsServiceObject,
143 gGraphicsStatsService_pullGraphicsStatsMethodID,
144 (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE),
145 reinterpret_cast<jlong>(data));
146 if (env->ExceptionCheck()) {
147 env->ExceptionDescribe();
148 env->ExceptionClear();
149 ALOGE("Failed to invoke graphicsstats service");
150 return AStatsManager_PULL_SKIP;
151 }
152 }
153 return AStatsManager_PULL_SUCCESS;
154}
155
156// Register a puller for GRAPHICS_STATS atom with the statsd service.
157static void nativeInit(JNIEnv* env, jobject javaObject) {
158 gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject);
159 AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
160 AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds
161 AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds
162
163 AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS,
164 &graphicsStatsPullCallback, metadata, nullptr);
165
166 AStatsManager_PullAtomMetadata_release(metadata);
167}
168
169static void nativeDestructor(JNIEnv* env, jobject javaObject) {
170 AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS);
171 env->DeleteGlobalRef(gGraphicsStatsServiceObject);
172 gGraphicsStatsServiceObject = nullptr;
173}
174
175static const JNINativeMethod sMethods[] =
176 {{"nGetAshmemSize", "()I", (void*)getAshmemSize},
177 {"nCreateDump", "(IZ)J", (void*)createDump},
178 {"nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)addToDump},
179 {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump},
180 {"nFinishDump", "(J)V", (void*)finishDump},
181 {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory},
182 {"nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)saveBuffer},
183 {"nativeInit", "()V", (void*)nativeInit},
184 {"nativeDestructor", "()V", (void*)nativeDestructor}};
185
186int register_android_graphics_GraphicsStatsService(JNIEnv* env) {
187 jclass graphicsStatsService_class =
188 FindClassOrDie(env, "android/graphics/GraphicsStatsService");
189 gGraphicsStatsService_pullGraphicsStatsMethodID =
190 GetMethodIDOrDie(env, graphicsStatsService_class, "pullGraphicsStats", "(ZJ)V");
191 return jniRegisterNativeMethods(env, "android/graphics/GraphicsStatsService", sMethods,
192 NELEM(sMethods));
193}
194
195} // namespace android