xref: /aosp_15_r20/frameworks/base/libs/hwui/jni/GraphicsStatsService.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
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 #include <JankTracker.h>
18 #include <log/log.h>
19 #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>
24 #include <statslog_hwui.h>
25 
26 #include "GraphicsJNI.h"
27 #include "android/graphics/jni_runtime.h"
28 
29 namespace android {
30 
31 using namespace android::uirenderer;
32 
getAshmemSize(JNIEnv *,jobject)33 static jint getAshmemSize(JNIEnv*, jobject) {
34     return sizeof(ProfileData);
35 }
36 
createDump(JNIEnv *,jobject,jint fd,jboolean isProto)37 static 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 
addToDump(JNIEnv * env,jobject,jlong dumpPtr,jstring jpath,jint uid,jstring jpackage,jlong versionCode,jlong startTime,jlong endTime,jbyteArray jdata)45 static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jint uid,
46                       jstring jpackage, jlong versionCode, jlong startTime, jlong endTime,
47                       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, static_cast<uid_t>(uid), package, versionCode,
73                                     startTime, endTime, data);
74 }
75 
addFileToDump(JNIEnv * env,jobject,jlong dumpPtr,jstring jpath)76 static 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 
finishDump(JNIEnv *,jobject,jlong dumpPtr)84 static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
85     GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
86     GraphicsStatsService::finishDump(dump);
87 }
88 
finishDumpInMemory(JNIEnv * env,jobject,jlong dumpPtr,jlong pulledData,jboolean lastFullDay)89 static 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 
saveBuffer(JNIEnv * env,jobject clazz,jstring jpath,jint uid,jstring jpackage,jlong versionCode,jlong startTime,jlong endTime,jbyteArray jdata)96 static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jint uid, 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, static_cast<uid_t>(uid), package, versionCode, startTime,
112                                      endTime, data);
113 }
114 
115 static jobject gGraphicsStatsServiceObject = nullptr;
116 static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
117 
getJNIEnv()118 static JNIEnv* getJNIEnv() {
119     JavaVM* vm = GraphicsJNI::getJavaVM();
120     JNIEnv* env = nullptr;
121     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
122         if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
123             LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
124         }
125     }
126     return env;
127 }
128 
129 // graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom.
graphicsStatsPullCallback(int32_t atom_tag,AStatsEventList * data,void * cookie)130 static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag,
131                                                                       AStatsEventList* data,
132                                                                       void* cookie) {
133     JNIEnv* env = getJNIEnv();
134     if (!env) {
135         return false;
136     }
137     if (gGraphicsStatsServiceObject == nullptr) {
138         ALOGE("Failed to get graphicsstats service");
139         return AStatsManager_PULL_SKIP;
140     }
141 
142     for (bool lastFullDay : {true, false}) {
143         env->CallVoidMethod(gGraphicsStatsServiceObject,
144                             gGraphicsStatsService_pullGraphicsStatsMethodID,
145                             (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE),
146                             reinterpret_cast<jlong>(data));
147         if (env->ExceptionCheck()) {
148             env->ExceptionDescribe();
149             env->ExceptionClear();
150             ALOGE("Failed to invoke graphicsstats service");
151             return AStatsManager_PULL_SKIP;
152         }
153     }
154     return AStatsManager_PULL_SUCCESS;
155 }
156 
157 // Register a puller for GRAPHICS_STATS atom with the statsd service.
nativeInit(JNIEnv * env,jobject javaObject)158 static void nativeInit(JNIEnv* env, jobject javaObject) {
159     gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject);
160     AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
161     AStatsManager_PullAtomMetadata_setCoolDownMillis(metadata, 10);             // 10 milliseconds
162     AStatsManager_PullAtomMetadata_setTimeoutMillis(metadata, 2 * MS_PER_SEC);  // 2 seconds
163 
164     AStatsManager_setPullAtomCallback(stats::GRAPHICS_STATS, metadata, &graphicsStatsPullCallback,
165                                       nullptr);
166 
167     AStatsManager_PullAtomMetadata_release(metadata);
168 }
169 
nativeDestructor(JNIEnv * env,jobject javaObject)170 static void nativeDestructor(JNIEnv* env, jobject javaObject) {
171     AStatsManager_clearPullAtomCallback(stats::GRAPHICS_STATS);
172     env->DeleteGlobalRef(gGraphicsStatsServiceObject);
173     gGraphicsStatsServiceObject = nullptr;
174 }
175 
176 } // namespace android
177 using namespace android;
178 
179 static const JNINativeMethod sMethods[] = {
180         {"nGetAshmemSize", "()I", (void*)getAshmemSize},
181         {"nCreateDump", "(IZ)J", (void*)createDump},
182         {"nAddToDump", "(JLjava/lang/String;ILjava/lang/String;JJJ[B)V", (void*)addToDump},
183         {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump},
184         {"nFinishDump", "(J)V", (void*)finishDump},
185         {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory},
186         {"nSaveBuffer", "(Ljava/lang/String;ILjava/lang/String;JJJ[B)V", (void*)saveBuffer},
187         {"nativeInit", "()V", (void*)nativeInit},
188         {"nativeDestructor", "()V", (void*)nativeDestructor}};
189 
register_android_graphics_GraphicsStatsService(JNIEnv * env)190 int register_android_graphics_GraphicsStatsService(JNIEnv* env) {
191     jclass graphicsStatsService_class =
192             FindClassOrDie(env, "android/graphics/GraphicsStatsService");
193     gGraphicsStatsService_pullGraphicsStatsMethodID =
194             GetMethodIDOrDie(env, graphicsStatsService_class, "pullGraphicsStats", "(ZJ)V");
195     return jniRegisterNativeMethods(env, "android/graphics/GraphicsStatsService", sMethods,
196                                     NELEM(sMethods));
197 }
198