blob: e9259462bcac9b2287600ea75a14f182d9b081b2 [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
Derek Sollenberger5368eda2019-10-25 11:20:03 -040017#undef LOG_TAG
Stan Ilievc9043812020-02-03 16:57:09 -050018#define LOG_TAG "GraphicsStatsService"
19
20#include <JankTracker.h>
Stan Ilievc9043812020-02-03 16:57:09 -050021#include <log/log.h>
Stan Ilievc9043812020-02-03 16:57:09 -050022#include <nativehelper/ScopedPrimitiveArray.h>
23#include <nativehelper/ScopedUtfChars.h>
24#include <service/GraphicsStatsService.h>
25#include <stats_event.h>
26#include <stats_pull_atom_callback.h>
27#include <statslog.h>
Derek Sollenbergerc5882c42019-10-25 11:11:32 -040028#include "GraphicsJNI.h"
Stan Ilievc9043812020-02-03 16:57:09 -050029
30namespace android {
31
32using namespace android::uirenderer;
33
34static jint getAshmemSize(JNIEnv*, jobject) {
35 return sizeof(ProfileData);
36}
37
38static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) {
39 GraphicsStatsService::Dump* dump =
40 GraphicsStatsService::createDump(fd,
41 isProto ? GraphicsStatsService::DumpType::Protobuf
42 : GraphicsStatsService::DumpType::Text);
43 return reinterpret_cast<jlong>(dump);
44}
45
46static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
47 jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
48 std::string path;
49 const ProfileData* data = nullptr;
50 LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
51 ScopedByteArrayRO buffer{env};
52 if (jdata != nullptr) {
53 buffer.reset(jdata);
54 LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
55 "Buffer size %zu doesn't match expected %zu!", buffer.size(),
56 sizeof(ProfileData));
57 data = reinterpret_cast<const ProfileData*>(buffer.get());
58 }
59 if (jpath != nullptr) {
60 ScopedUtfChars pathChars(env, jpath);
61 LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(),
62 "Failed to get path chars");
63 path.assign(pathChars.c_str(), pathChars.size());
64 }
65 ScopedUtfChars packageChars(env, jpackage);
66 LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
67 "Failed to get path chars");
68 GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
69 LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
70
71 const std::string package(packageChars.c_str(), packageChars.size());
72 GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
73}
74
75static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
76 ScopedUtfChars pathChars(env, jpath);
77 LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
78 const std::string path(pathChars.c_str(), pathChars.size());
79 GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
80 GraphicsStatsService::addToDump(dump, path);
81}
82
83static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
84 GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
85 GraphicsStatsService::finishDump(dump);
86}
87
88static void finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr, jlong pulledData,
89 jboolean lastFullDay) {
90 GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
91 AStatsEventList* data = reinterpret_cast<AStatsEventList*>(pulledData);
92 GraphicsStatsService::finishDumpInMemory(dump, data, lastFullDay == JNI_TRUE);
93}
94
95static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
96 jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
97 ScopedByteArrayRO buffer(env, jdata);
98 LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
99 "Buffer size %zu doesn't match expected %zu!", buffer.size(),
100 sizeof(ProfileData));
101 ScopedUtfChars pathChars(env, jpath);
102 LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
103 ScopedUtfChars packageChars(env, jpackage);
104 LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
105 "Failed to get path chars");
106
107 const std::string path(pathChars.c_str(), pathChars.size());
108 const std::string package(packageChars.c_str(), packageChars.size());
109 const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get());
110 GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data);
111}
112
113static jobject gGraphicsStatsServiceObject = nullptr;
114static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
115
116static JNIEnv* getJNIEnv() {
Derek Sollenbergerc5882c42019-10-25 11:11:32 -0400117 JavaVM* vm = GraphicsJNI::getJavaVM();
Stan Ilievc9043812020-02-03 16:57:09 -0500118 JNIEnv* env = nullptr;
119 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
120 if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
121 LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
122 }
123 }
124 return env;
125}
126
127// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom.
128static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag,
129 AStatsEventList* data,
130 void* cookie) {
131 JNIEnv* env = getJNIEnv();
132 if (!env) {
133 return false;
134 }
135 if (gGraphicsStatsServiceObject == nullptr) {
136 ALOGE("Failed to get graphicsstats service");
137 return AStatsManager_PULL_SKIP;
138 }
139
140 for (bool lastFullDay : {true, false}) {
141 env->CallVoidMethod(gGraphicsStatsServiceObject,
142 gGraphicsStatsService_pullGraphicsStatsMethodID,
143 (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE),
144 reinterpret_cast<jlong>(data));
145 if (env->ExceptionCheck()) {
146 env->ExceptionDescribe();
147 env->ExceptionClear();
148 ALOGE("Failed to invoke graphicsstats service");
149 return AStatsManager_PULL_SKIP;
150 }
151 }
152 return AStatsManager_PULL_SUCCESS;
153}
154
155// Register a puller for GRAPHICS_STATS atom with the statsd service.
156static void nativeInit(JNIEnv* env, jobject javaObject) {
157 gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject);
158 AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
159 AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds
160 AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds
161
162 AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS,
163 &graphicsStatsPullCallback, metadata, nullptr);
164
165 AStatsManager_PullAtomMetadata_release(metadata);
166}
167
168static void nativeDestructor(JNIEnv* env, jobject javaObject) {
169 AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS);
170 env->DeleteGlobalRef(gGraphicsStatsServiceObject);
171 gGraphicsStatsServiceObject = nullptr;
172}
173
174static const JNINativeMethod sMethods[] =
175 {{"nGetAshmemSize", "()I", (void*)getAshmemSize},
176 {"nCreateDump", "(IZ)J", (void*)createDump},
177 {"nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)addToDump},
178 {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump},
179 {"nFinishDump", "(J)V", (void*)finishDump},
180 {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory},
181 {"nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)saveBuffer},
182 {"nativeInit", "()V", (void*)nativeInit},
183 {"nativeDestructor", "()V", (void*)nativeDestructor}};
184
185int register_android_graphics_GraphicsStatsService(JNIEnv* env) {
186 jclass graphicsStatsService_class =
187 FindClassOrDie(env, "android/graphics/GraphicsStatsService");
188 gGraphicsStatsService_pullGraphicsStatsMethodID =
189 GetMethodIDOrDie(env, graphicsStatsService_class, "pullGraphicsStats", "(ZJ)V");
190 return jniRegisterNativeMethods(env, "android/graphics/GraphicsStatsService", sMethods,
191 NELEM(sMethods));
192}
193
194} // namespace android