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