1 /*
2  * Copyright (C) 2021 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 package com.android.internal.os;
18 
19 import android.annotation.Nullable;
20 
21 /**
22  * CPU tracking using eBPF.
23  *
24  * The tracking state and data about available frequencies are cached to avoid JNI calls and
25  * creating temporary arrays. The data is stored in a format that is convenient for metrics
26  * computation.
27  *
28  * Synchronization is not needed because the underlying native library can be invoked concurrently
29  * and getters are idempotent.
30  */
31 public final class KernelCpuBpfTracking {
32     private static boolean sTracking = false;
33 
34     /** Cached mapping from frequency index to frequency in kHz. */
35     private static long[] sFreqs = null;
36 
37     /** Cached mapping from frequency index to CPU cluster / policy. */
38     private static int[] sFreqsClusters = null;
39 
KernelCpuBpfTracking()40     private KernelCpuBpfTracking() {
41     }
42 
43     /** Returns whether CPU tracking using eBPF is supported. */
isSupported()44     public static native boolean isSupported();
45 
46     /** Starts CPU tracking using eBPF. */
startTracking()47     public static boolean startTracking() {
48         if (!sTracking) {
49             sTracking = startTrackingInternal();
50         }
51         return sTracking;
52     }
53 
startTrackingInternal()54     private static native boolean startTrackingInternal();
55 
56     /** Returns frequencies in kHz on which CPU is tracked. Empty if not supported. */
getFreqs()57     public static long[] getFreqs() {
58         if (sFreqs == null) {
59             long[] freqs = getFreqsInternal();
60             if (freqs == null) {
61                 return new long[0];
62             }
63             sFreqs = freqs;
64         }
65         return sFreqs;
66     }
67 
68     @Nullable
getFreqsInternal()69     static native long[] getFreqsInternal();
70 
71     /**
72      * Returns the cluster (policy) number  for each frequency on which CPU is tracked. Empty if
73      * not supported.
74      */
getFreqsClusters()75     public static int[] getFreqsClusters() {
76         if (sFreqsClusters == null) {
77             int[] freqsClusters = getFreqsClustersInternal();
78             if (freqsClusters == null) {
79                 return new int[0];
80             }
81             sFreqsClusters = freqsClusters;
82         }
83         return sFreqsClusters;
84     }
85 
86     @Nullable
getFreqsClustersInternal()87     private static native int[] getFreqsClustersInternal();
88 
89     /** Returns the number of clusters (policies). */
getClusters()90     public static int getClusters() {
91         int[] freqClusters = getFreqsClusters();
92         return freqClusters.length > 0 ? freqClusters[freqClusters.length - 1] + 1 : 0;
93     }
94 }
95