1 /*
2 * Copyright 2022, 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 <jni.h>
18 #include <core_jni_helpers.h>
19 #include <utils/misc.h>
20 #include <androidfw/ResourceTimer.h>
21
22 namespace android {
23
24 // ----------------------------------------------------------------------------
25
26 static struct {
27 jfieldID maxTimer;
28 jfieldID maxBuckets;
29 jfieldID maxLargest;
30 jfieldID timers;
31 } gConfigOffsets;
32
33 static struct {
34 jfieldID count;
35 jfieldID total;
36 jfieldID mintime;
37 jfieldID maxtime;
38 jfieldID largest;
39 jfieldID percentile;
40 } gTimerOffsets;
41
42 // ----------------------------------------------------------------------------
43
44
NativeGetTimers(JNIEnv * env,jobject,jobjectArray timer,jboolean reset)45 static int NativeGetTimers(JNIEnv* env, jobject /*clazz*/, jobjectArray timer, jboolean reset) {
46 size_t size = ResourceTimer::counterSize;
47 if (jsize st = env->GetArrayLength(timer); st < size) {
48 // Shrink the size to the minimum of the available counters and the available space.
49 size = st;
50 }
51 for (size_t i = 0; i < size; i++) {
52 ResourceTimer::Timer src;
53 ResourceTimer::copy(i, src, reset);
54 jobject dst = env->GetObjectArrayElement(timer, i);
55 env->SetIntField(dst, gTimerOffsets.count, src.count);
56 if (src.count == 0) {
57 continue;
58 }
59
60 src.compute();
61 env->SetIntField(dst, gTimerOffsets.count, src.count);
62 env->SetLongField(dst, gTimerOffsets.total, src.total);
63 env->SetIntField(dst, gTimerOffsets.mintime, src.mintime);
64 env->SetIntField(dst, gTimerOffsets.maxtime, src.maxtime);
65 jintArray percentile =
66 reinterpret_cast<jintArray>(env->GetObjectField(dst, gTimerOffsets.percentile));
67 env->SetIntArrayRegion(percentile, 0, 1, &src.pvalues.p50.nominal);
68 env->SetIntArrayRegion(percentile, 1, 1, &src.pvalues.p90.nominal);
69 env->SetIntArrayRegion(percentile, 2, 1, &src.pvalues.p95.nominal);
70 env->SetIntArrayRegion(percentile, 3, 1, &src.pvalues.p99.nominal);
71 jintArray largest =
72 reinterpret_cast<jintArray>(env->GetObjectField(dst, gTimerOffsets.largest));
73 env->SetIntArrayRegion(largest, 0, ResourceTimer::Timer::MaxLargest, src.largest);
74 }
75 return size;
76 }
77
counterName(JNIEnv * env,int counter)78 static jstring counterName(JNIEnv *env, int counter) {
79 char const *s = ResourceTimer::toString(static_cast<ResourceTimer::Counter>(counter));
80 return env->NewStringUTF(s);
81 }
82
NativeEnableTimers(JNIEnv * env,jobject,jobject config)83 static int NativeEnableTimers(JNIEnv* env, jobject /*clazz*/, jobject config) {
84 ResourceTimer::enable();
85
86 env->SetIntField(config, gConfigOffsets.maxTimer, ResourceTimer::counterSize);
87 env->SetIntField(config, gConfigOffsets.maxBuckets, 4); // Number of ints in PValues
88 env->SetIntField(config, gConfigOffsets.maxLargest, ResourceTimer::Timer::MaxLargest);
89
90 jclass str = env->FindClass("java/lang/String");
91 jstring empty = counterName(env, 0);
92 jobjectArray timers = env->NewObjectArray(ResourceTimer::counterSize, str, empty);
93 for (int i = 0; i < ResourceTimer::counterSize; i++) {
94 env->SetObjectArrayElement(timers, i, counterName(env, i));
95 }
96 env->SetObjectField(config, gConfigOffsets.timers, timers);
97 return 0;
98 }
99
100 // ----------------------------------------------------------------------------
101
102 // JNI registration.
103 static const JNINativeMethod gResourceTimerMethods[] = {
104 {"nativeEnableTimers", "(Landroid/content/res/ResourceTimer$Config;)I",
105 (void *) NativeEnableTimers},
106 {"nativeGetTimers", "([Landroid/content/res/ResourceTimer$Timer;Z)I",
107 (void *) NativeGetTimers},
108 };
109
register_android_content_res_ResourceTimer(JNIEnv * env)110 int register_android_content_res_ResourceTimer(JNIEnv* env) {
111 jclass config = FindClassOrDie(env, "android/content/res/ResourceTimer$Config");
112 gConfigOffsets.maxTimer = GetFieldIDOrDie(env, config, "maxTimer", "I");
113 gConfigOffsets.maxBuckets = GetFieldIDOrDie(env, config, "maxBuckets", "I");
114 gConfigOffsets.maxLargest = GetFieldIDOrDie(env, config, "maxLargest", "I");
115 gConfigOffsets.timers = GetFieldIDOrDie(env, config, "timers", "[Ljava/lang/String;");
116
117 jclass timers = FindClassOrDie(env, "android/content/res/ResourceTimer$Timer");
118 gTimerOffsets.count = GetFieldIDOrDie(env, timers, "count", "I");
119 gTimerOffsets.total = GetFieldIDOrDie(env, timers, "total", "J");
120 gTimerOffsets.mintime = GetFieldIDOrDie(env, timers, "mintime", "I");
121 gTimerOffsets.maxtime = GetFieldIDOrDie(env, timers, "maxtime", "I");
122 gTimerOffsets.largest = GetFieldIDOrDie(env, timers, "largest", "[I");
123 gTimerOffsets.percentile = GetFieldIDOrDie(env, timers, "percentile", "[I");
124
125 return RegisterMethodsOrDie(env, "android/content/res/ResourceTimer", gResourceTimerMethods,
126 NELEM(gResourceTimerMethods));
127 }
128
129 }; // namespace android
130