1*1783903dSAndroid Build Coastguard Worker /*
2*1783903dSAndroid Build Coastguard Worker * timeInState eBPF program
3*1783903dSAndroid Build Coastguard Worker *
4*1783903dSAndroid Build Coastguard Worker * Copyright (C) 2018 Google
5*1783903dSAndroid Build Coastguard Worker *
6*1783903dSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or
7*1783903dSAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License version
8*1783903dSAndroid Build Coastguard Worker * 2 as published by the Free Software Foundation.
9*1783903dSAndroid Build Coastguard Worker *
10*1783903dSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
11*1783903dSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*1783903dSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*1783903dSAndroid Build Coastguard Worker * GNU General Public License for more details.
14*1783903dSAndroid Build Coastguard Worker *
15*1783903dSAndroid Build Coastguard Worker */
16*1783903dSAndroid Build Coastguard Worker
17*1783903dSAndroid Build Coastguard Worker #include <android_bpf_defs.h>
18*1783903dSAndroid Build Coastguard Worker #include <bpf_timeinstate.h>
19*1783903dSAndroid Build Coastguard Worker #include <errno.h>
20*1783903dSAndroid Build Coastguard Worker
21*1783903dSAndroid Build Coastguard Worker #ifdef ENABLE_LIBBPF
22*1783903dSAndroid Build Coastguard Worker #include <linux/bpf.h>
23*1783903dSAndroid Build Coastguard Worker #include <private/android_filesystem_config.h>
24*1783903dSAndroid Build Coastguard Worker #include <stdbool.h>
25*1783903dSAndroid Build Coastguard Worker #endif // ENABLE_LIBBPF
26*1783903dSAndroid Build Coastguard Worker
27*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GRW(total_time_in_state_map, PERCPU_ARRAY, uint32_t, uint64_t, MAX_FREQS_FOR_TOTAL,
28*1783903dSAndroid Build Coastguard Worker AID_SYSTEM)
29*1783903dSAndroid Build Coastguard Worker
30*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GRW(uid_time_in_state_map, PERCPU_HASH, time_key_t, tis_val_t, 1024, AID_SYSTEM)
31*1783903dSAndroid Build Coastguard Worker
32*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GRW(uid_concurrent_times_map, PERCPU_HASH, time_key_t, concurrent_val_t, 1024,
33*1783903dSAndroid Build Coastguard Worker AID_SYSTEM)
34*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GRW(uid_last_update_map, HASH, uint32_t, uint64_t, 1024, AID_SYSTEM)
35*1783903dSAndroid Build Coastguard Worker
36*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(cpu_last_update_map, PERCPU_ARRAY, uint32_t, uint64_t, 1, AID_SYSTEM)
37*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(cpu_last_pid_map, PERCPU_ARRAY, uint32_t, pid_t, 1, AID_SYSTEM)
38*1783903dSAndroid Build Coastguard Worker
39*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(cpu_policy_map, ARRAY, uint32_t, uint32_t, 1024, AID_SYSTEM)
40*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(policy_freq_idx_map, ARRAY, uint32_t, uint8_t, 1024, AID_SYSTEM)
41*1783903dSAndroid Build Coastguard Worker
42*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(freq_to_idx_map, HASH, freq_idx_key_t, uint8_t, 2048, AID_SYSTEM)
43*1783903dSAndroid Build Coastguard Worker
44*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(nr_active_map, ARRAY, uint32_t, uint32_t, 1, AID_SYSTEM)
45*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(policy_nr_active_map, ARRAY, uint32_t, uint32_t, 1024, AID_SYSTEM)
46*1783903dSAndroid Build Coastguard Worker
47*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(pid_tracked_hash_map, HASH, uint32_t, pid_t, MAX_TRACKED_PIDS, AID_SYSTEM)
48*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(pid_tracked_map, ARRAY, uint32_t, tracked_pid_t, MAX_TRACKED_PIDS, AID_SYSTEM)
49*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GWO(pid_task_aggregation_map, HASH, pid_t, uint16_t, 1024, AID_SYSTEM)
50*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_MAP_GRO(pid_time_in_state_map, PERCPU_HASH, aggregated_task_tis_key_t, tis_val_t, 1024,
51*1783903dSAndroid Build Coastguard Worker AID_SYSTEM)
52*1783903dSAndroid Build Coastguard Worker
53*1783903dSAndroid Build Coastguard Worker struct switch_args {
54*1783903dSAndroid Build Coastguard Worker unsigned long long ignore;
55*1783903dSAndroid Build Coastguard Worker char prev_comm[16];
56*1783903dSAndroid Build Coastguard Worker int prev_pid;
57*1783903dSAndroid Build Coastguard Worker int prev_prio;
58*1783903dSAndroid Build Coastguard Worker long long prev_state;
59*1783903dSAndroid Build Coastguard Worker char next_comm[16];
60*1783903dSAndroid Build Coastguard Worker int next_pid;
61*1783903dSAndroid Build Coastguard Worker int next_prio;
62*1783903dSAndroid Build Coastguard Worker };
63*1783903dSAndroid Build Coastguard Worker
update_uid(uint32_t uid,uint64_t delta,uint64_t time,uint8_t freq_idx,uint32_t active,uint32_t policy_active)64*1783903dSAndroid Build Coastguard Worker static inline __always_inline void update_uid(uint32_t uid, uint64_t delta, uint64_t time,
65*1783903dSAndroid Build Coastguard Worker uint8_t freq_idx, uint32_t active,
66*1783903dSAndroid Build Coastguard Worker uint32_t policy_active) {
67*1783903dSAndroid Build Coastguard Worker time_key_t key = {.uid = uid, .bucket = freq_idx / FREQS_PER_ENTRY};
68*1783903dSAndroid Build Coastguard Worker tis_val_t* val = bpf_uid_time_in_state_map_lookup_elem(&key);
69*1783903dSAndroid Build Coastguard Worker if (!val) {
70*1783903dSAndroid Build Coastguard Worker tis_val_t zero_val = {.ar = {0}};
71*1783903dSAndroid Build Coastguard Worker bpf_uid_time_in_state_map_update_elem(&key, &zero_val, BPF_NOEXIST);
72*1783903dSAndroid Build Coastguard Worker val = bpf_uid_time_in_state_map_lookup_elem(&key);
73*1783903dSAndroid Build Coastguard Worker }
74*1783903dSAndroid Build Coastguard Worker if (val) val->ar[freq_idx % FREQS_PER_ENTRY] += delta;
75*1783903dSAndroid Build Coastguard Worker
76*1783903dSAndroid Build Coastguard Worker key.bucket = active / CPUS_PER_ENTRY;
77*1783903dSAndroid Build Coastguard Worker concurrent_val_t* ct = bpf_uid_concurrent_times_map_lookup_elem(&key);
78*1783903dSAndroid Build Coastguard Worker if (!ct) {
79*1783903dSAndroid Build Coastguard Worker concurrent_val_t zero_val = {.active = {0}, .policy = {0}};
80*1783903dSAndroid Build Coastguard Worker bpf_uid_concurrent_times_map_update_elem(&key, &zero_val, BPF_NOEXIST);
81*1783903dSAndroid Build Coastguard Worker ct = bpf_uid_concurrent_times_map_lookup_elem(&key);
82*1783903dSAndroid Build Coastguard Worker }
83*1783903dSAndroid Build Coastguard Worker if (ct) ct->active[active % CPUS_PER_ENTRY] += delta;
84*1783903dSAndroid Build Coastguard Worker
85*1783903dSAndroid Build Coastguard Worker if (policy_active / CPUS_PER_ENTRY != key.bucket) {
86*1783903dSAndroid Build Coastguard Worker key.bucket = policy_active / CPUS_PER_ENTRY;
87*1783903dSAndroid Build Coastguard Worker ct = bpf_uid_concurrent_times_map_lookup_elem(&key);
88*1783903dSAndroid Build Coastguard Worker if (!ct) {
89*1783903dSAndroid Build Coastguard Worker concurrent_val_t zero_val = {.active = {0}, .policy = {0}};
90*1783903dSAndroid Build Coastguard Worker bpf_uid_concurrent_times_map_update_elem(&key, &zero_val, BPF_NOEXIST);
91*1783903dSAndroid Build Coastguard Worker ct = bpf_uid_concurrent_times_map_lookup_elem(&key);
92*1783903dSAndroid Build Coastguard Worker }
93*1783903dSAndroid Build Coastguard Worker }
94*1783903dSAndroid Build Coastguard Worker if (ct) ct->policy[policy_active % CPUS_PER_ENTRY] += delta;
95*1783903dSAndroid Build Coastguard Worker uint64_t* uid_last_update = bpf_uid_last_update_map_lookup_elem(&uid);
96*1783903dSAndroid Build Coastguard Worker if (uid_last_update) {
97*1783903dSAndroid Build Coastguard Worker *uid_last_update = time;
98*1783903dSAndroid Build Coastguard Worker } else {
99*1783903dSAndroid Build Coastguard Worker bpf_uid_last_update_map_update_elem(&uid, &time, BPF_NOEXIST);
100*1783903dSAndroid Build Coastguard Worker }
101*1783903dSAndroid Build Coastguard Worker return;
102*1783903dSAndroid Build Coastguard Worker }
103*1783903dSAndroid Build Coastguard Worker
104*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_PROG("tracepoint/sched/sched_switch", AID_ROOT, AID_SYSTEM,
105*1783903dSAndroid Build Coastguard Worker tracepoint_sched_sched_switch)
106*1783903dSAndroid Build Coastguard Worker (struct switch_args* args) {
107*1783903dSAndroid Build Coastguard Worker const int ALLOW = 1; // return 1 to avoid blocking simpleperf from receiving events.
108*1783903dSAndroid Build Coastguard Worker uint32_t zero = 0;
109*1783903dSAndroid Build Coastguard Worker uint64_t* last = bpf_cpu_last_update_map_lookup_elem(&zero);
110*1783903dSAndroid Build Coastguard Worker if (!last) return ALLOW;
111*1783903dSAndroid Build Coastguard Worker uint64_t old_last = *last;
112*1783903dSAndroid Build Coastguard Worker uint64_t time = bpf_ktime_get_ns();
113*1783903dSAndroid Build Coastguard Worker *last = time;
114*1783903dSAndroid Build Coastguard Worker
115*1783903dSAndroid Build Coastguard Worker // With suspend-to-ram, it's possible to see prev_pid==0 twice in a row on the same CPU. Add a
116*1783903dSAndroid Build Coastguard Worker // check to ensure prev_pid matches the previous next_pid to avoid incorrectly incrementing our
117*1783903dSAndroid Build Coastguard Worker // active CPU counts a second time in this scenario.
118*1783903dSAndroid Build Coastguard Worker pid_t *cpu_pidp = bpf_cpu_last_pid_map_lookup_elem(&zero);
119*1783903dSAndroid Build Coastguard Worker if (!cpu_pidp) return ALLOW;
120*1783903dSAndroid Build Coastguard Worker pid_t cpu_pid = *cpu_pidp;
121*1783903dSAndroid Build Coastguard Worker *cpu_pidp = args->next_pid;
122*1783903dSAndroid Build Coastguard Worker if (old_last && args->prev_pid != cpu_pid) return ALLOW;
123*1783903dSAndroid Build Coastguard Worker
124*1783903dSAndroid Build Coastguard Worker uint32_t* active = bpf_nr_active_map_lookup_elem(&zero);
125*1783903dSAndroid Build Coastguard Worker if (!active) return ALLOW;
126*1783903dSAndroid Build Coastguard Worker
127*1783903dSAndroid Build Coastguard Worker uint32_t cpu = bpf_get_smp_processor_id();
128*1783903dSAndroid Build Coastguard Worker uint32_t* policyp = bpf_cpu_policy_map_lookup_elem(&cpu);
129*1783903dSAndroid Build Coastguard Worker if (!policyp) return ALLOW;
130*1783903dSAndroid Build Coastguard Worker uint32_t policy = *policyp;
131*1783903dSAndroid Build Coastguard Worker
132*1783903dSAndroid Build Coastguard Worker uint32_t* policy_active = bpf_policy_nr_active_map_lookup_elem(&policy);
133*1783903dSAndroid Build Coastguard Worker if (!policy_active) return ALLOW;
134*1783903dSAndroid Build Coastguard Worker
135*1783903dSAndroid Build Coastguard Worker uint32_t nactive = *active - 1;
136*1783903dSAndroid Build Coastguard Worker uint32_t policy_nactive = *policy_active - 1;
137*1783903dSAndroid Build Coastguard Worker
138*1783903dSAndroid Build Coastguard Worker if (!args->prev_pid || (!old_last && args->next_pid)) {
139*1783903dSAndroid Build Coastguard Worker __sync_fetch_and_add(active, 1);
140*1783903dSAndroid Build Coastguard Worker __sync_fetch_and_add(policy_active, 1);
141*1783903dSAndroid Build Coastguard Worker }
142*1783903dSAndroid Build Coastguard Worker
143*1783903dSAndroid Build Coastguard Worker // Return here in 2 scenarios:
144*1783903dSAndroid Build Coastguard Worker // 1) prev_pid == 0, so we're exiting idle. No UID stats need updating, and active CPUs can't be
145*1783903dSAndroid Build Coastguard Worker // decreasing.
146*1783903dSAndroid Build Coastguard Worker // 2) old_last == 0, so this is the first time we've seen this CPU. Any delta will be invalid,
147*1783903dSAndroid Build Coastguard Worker // and our active CPU counts don't include this CPU yet so we shouldn't decrement them even
148*1783903dSAndroid Build Coastguard Worker // if we're going idle.
149*1783903dSAndroid Build Coastguard Worker if (!args->prev_pid || !old_last) return ALLOW;
150*1783903dSAndroid Build Coastguard Worker
151*1783903dSAndroid Build Coastguard Worker if (!args->next_pid) {
152*1783903dSAndroid Build Coastguard Worker __sync_fetch_and_add(active, -1);
153*1783903dSAndroid Build Coastguard Worker __sync_fetch_and_add(policy_active, -1);
154*1783903dSAndroid Build Coastguard Worker }
155*1783903dSAndroid Build Coastguard Worker
156*1783903dSAndroid Build Coastguard Worker uint8_t* freq_idxp = bpf_policy_freq_idx_map_lookup_elem(&policy);
157*1783903dSAndroid Build Coastguard Worker if (!freq_idxp || !*freq_idxp) return ALLOW;
158*1783903dSAndroid Build Coastguard Worker // freq_to_idx_map uses 1 as its minimum index so that *freq_idxp == 0 only when uninitialized
159*1783903dSAndroid Build Coastguard Worker uint8_t freq_idx = *freq_idxp - 1;
160*1783903dSAndroid Build Coastguard Worker
161*1783903dSAndroid Build Coastguard Worker // The bpf_get_current_uid_gid() helper function returns a u64 value, with the lower 32 bits
162*1783903dSAndroid Build Coastguard Worker // containing the UID and the upper 32 bits containing the GID. Additionally, in rare cases,
163*1783903dSAndroid Build Coastguard Worker // (usually something is very wrong with the kernel) the helper can return -EINVAL, in which
164*1783903dSAndroid Build Coastguard Worker // case we should just return early.
165*1783903dSAndroid Build Coastguard Worker unsigned long long uid_gid = bpf_get_current_uid_gid();
166*1783903dSAndroid Build Coastguard Worker if (uid_gid == (unsigned long long)(-EINVAL)) return ALLOW;
167*1783903dSAndroid Build Coastguard Worker
168*1783903dSAndroid Build Coastguard Worker // Mask out the uid part of the uid_gid value returned from the kernel.
169*1783903dSAndroid Build Coastguard Worker uint32_t uid = uid_gid & 0xFFFFFFFF;
170*1783903dSAndroid Build Coastguard Worker
171*1783903dSAndroid Build Coastguard Worker uint64_t delta = time - old_last;
172*1783903dSAndroid Build Coastguard Worker
173*1783903dSAndroid Build Coastguard Worker // For UIDs in the SDK sandbox range, we account per-UID times twice, both to the corresponding
174*1783903dSAndroid Build Coastguard Worker // app uid and to the "virtual" UID AID_SDK_SANDBOX which is reserved for collecting total times
175*1783903dSAndroid Build Coastguard Worker // across all SDK sandbox UIDs. Special handling for this reserved UID in framework code
176*1783903dSAndroid Build Coastguard Worker // prevents double counting in systemwide totals.
177*1783903dSAndroid Build Coastguard Worker if (((uid % AID_USER_OFFSET) >= AID_SDK_SANDBOX_PROCESS_START) &&
178*1783903dSAndroid Build Coastguard Worker ((uid % AID_USER_OFFSET) <= AID_SDK_SANDBOX_PROCESS_END)) {
179*1783903dSAndroid Build Coastguard Worker uid -= AID_SDK_SANDBOX_PROCESS_START - AID_APP_START;
180*1783903dSAndroid Build Coastguard Worker update_uid(uid, delta, time, freq_idx, nactive, policy_nactive);
181*1783903dSAndroid Build Coastguard Worker update_uid(AID_SDK_SANDBOX, delta, time, freq_idx, nactive, policy_nactive);
182*1783903dSAndroid Build Coastguard Worker } else {
183*1783903dSAndroid Build Coastguard Worker update_uid(uid, delta, time, freq_idx, nactive, policy_nactive);
184*1783903dSAndroid Build Coastguard Worker }
185*1783903dSAndroid Build Coastguard Worker
186*1783903dSAndroid Build Coastguard Worker // Add delta to total.
187*1783903dSAndroid Build Coastguard Worker const uint32_t total_freq_idx = freq_idx < MAX_FREQS_FOR_TOTAL ? freq_idx :
188*1783903dSAndroid Build Coastguard Worker MAX_FREQS_FOR_TOTAL - 1;
189*1783903dSAndroid Build Coastguard Worker uint64_t* total = bpf_total_time_in_state_map_lookup_elem(&total_freq_idx);
190*1783903dSAndroid Build Coastguard Worker if (total) *total += delta;
191*1783903dSAndroid Build Coastguard Worker
192*1783903dSAndroid Build Coastguard Worker const int pid = args->prev_pid;
193*1783903dSAndroid Build Coastguard Worker const pid_t tgid = bpf_get_current_pid_tgid() >> 32;
194*1783903dSAndroid Build Coastguard Worker bool is_tgid_tracked = false;
195*1783903dSAndroid Build Coastguard Worker
196*1783903dSAndroid Build Coastguard Worker // eBPF verifier does not currently allow loops.
197*1783903dSAndroid Build Coastguard Worker // Instruct the C compiler to unroll the loop into a series of steps.
198*1783903dSAndroid Build Coastguard Worker #pragma unroll
199*1783903dSAndroid Build Coastguard Worker for (uint32_t index = 0; index < MAX_TRACKED_PIDS; index++) {
200*1783903dSAndroid Build Coastguard Worker const uint32_t key = index;
201*1783903dSAndroid Build Coastguard Worker tracked_pid_t* tracked_pid = bpf_pid_tracked_map_lookup_elem(&key);
202*1783903dSAndroid Build Coastguard Worker if (!tracked_pid) continue;
203*1783903dSAndroid Build Coastguard Worker if (tracked_pid->state == TRACKED_PID_STATE_UNUSED) {
204*1783903dSAndroid Build Coastguard Worker // Reached the end of the list
205*1783903dSAndroid Build Coastguard Worker break;
206*1783903dSAndroid Build Coastguard Worker }
207*1783903dSAndroid Build Coastguard Worker
208*1783903dSAndroid Build Coastguard Worker if (tracked_pid->state == TRACKED_PID_STATE_ACTIVE && tracked_pid->pid == tgid) {
209*1783903dSAndroid Build Coastguard Worker is_tgid_tracked = true;
210*1783903dSAndroid Build Coastguard Worker break;
211*1783903dSAndroid Build Coastguard Worker }
212*1783903dSAndroid Build Coastguard Worker }
213*1783903dSAndroid Build Coastguard Worker
214*1783903dSAndroid Build Coastguard Worker if (is_tgid_tracked) {
215*1783903dSAndroid Build Coastguard Worker // If this process is marked for time-in-state tracking, aggregate the CPU time-in-state
216*1783903dSAndroid Build Coastguard Worker // with other threads sharing the same TGID and aggregation key.
217*1783903dSAndroid Build Coastguard Worker uint16_t* aggregation_key = bpf_pid_task_aggregation_map_lookup_elem(&pid);
218*1783903dSAndroid Build Coastguard Worker aggregated_task_tis_key_t task_key = {
219*1783903dSAndroid Build Coastguard Worker .tgid = tgid,
220*1783903dSAndroid Build Coastguard Worker .aggregation_key = aggregation_key ? *aggregation_key : 0,
221*1783903dSAndroid Build Coastguard Worker .bucket = freq_idx / FREQS_PER_ENTRY};
222*1783903dSAndroid Build Coastguard Worker tis_val_t* task_val = bpf_pid_time_in_state_map_lookup_elem(&task_key);
223*1783903dSAndroid Build Coastguard Worker if (!task_val) {
224*1783903dSAndroid Build Coastguard Worker tis_val_t zero_val = {.ar = {0}};
225*1783903dSAndroid Build Coastguard Worker bpf_pid_time_in_state_map_update_elem(&task_key, &zero_val, BPF_NOEXIST);
226*1783903dSAndroid Build Coastguard Worker task_val = bpf_pid_time_in_state_map_lookup_elem(&task_key);
227*1783903dSAndroid Build Coastguard Worker }
228*1783903dSAndroid Build Coastguard Worker if (task_val) task_val->ar[freq_idx % FREQS_PER_ENTRY] += delta;
229*1783903dSAndroid Build Coastguard Worker }
230*1783903dSAndroid Build Coastguard Worker return ALLOW;
231*1783903dSAndroid Build Coastguard Worker }
232*1783903dSAndroid Build Coastguard Worker
233*1783903dSAndroid Build Coastguard Worker struct cpufreq_args {
234*1783903dSAndroid Build Coastguard Worker unsigned long long ignore;
235*1783903dSAndroid Build Coastguard Worker unsigned int state;
236*1783903dSAndroid Build Coastguard Worker unsigned int cpu_id;
237*1783903dSAndroid Build Coastguard Worker };
238*1783903dSAndroid Build Coastguard Worker
239*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_PROG("tracepoint/power/cpu_frequency", AID_ROOT, AID_SYSTEM,
240*1783903dSAndroid Build Coastguard Worker tracepoint_power_cpu_frequency)
241*1783903dSAndroid Build Coastguard Worker (struct cpufreq_args* args) {
242*1783903dSAndroid Build Coastguard Worker const int ALLOW = 1; // return 1 to avoid blocking simpleperf from receiving events.
243*1783903dSAndroid Build Coastguard Worker uint32_t cpu = args->cpu_id;
244*1783903dSAndroid Build Coastguard Worker unsigned int new = args->state;
245*1783903dSAndroid Build Coastguard Worker uint32_t* policyp = bpf_cpu_policy_map_lookup_elem(&cpu);
246*1783903dSAndroid Build Coastguard Worker if (!policyp) return ALLOW;
247*1783903dSAndroid Build Coastguard Worker uint32_t policy = *policyp;
248*1783903dSAndroid Build Coastguard Worker freq_idx_key_t key = {.policy = policy, .freq = new};
249*1783903dSAndroid Build Coastguard Worker uint8_t* idxp = bpf_freq_to_idx_map_lookup_elem(&key);
250*1783903dSAndroid Build Coastguard Worker if (!idxp) return ALLOW;
251*1783903dSAndroid Build Coastguard Worker uint8_t idx = *idxp;
252*1783903dSAndroid Build Coastguard Worker bpf_policy_freq_idx_map_update_elem(&policy, &idx, BPF_ANY);
253*1783903dSAndroid Build Coastguard Worker return ALLOW;
254*1783903dSAndroid Build Coastguard Worker }
255*1783903dSAndroid Build Coastguard Worker
256*1783903dSAndroid Build Coastguard Worker // The format of the sched/sched_process_free event is described in
257*1783903dSAndroid Build Coastguard Worker // adb shell cat /d/tracing/events/sched/sched_process_free/format
258*1783903dSAndroid Build Coastguard Worker struct sched_process_free_args {
259*1783903dSAndroid Build Coastguard Worker unsigned long long ignore;
260*1783903dSAndroid Build Coastguard Worker char comm[16];
261*1783903dSAndroid Build Coastguard Worker pid_t pid;
262*1783903dSAndroid Build Coastguard Worker int prio;
263*1783903dSAndroid Build Coastguard Worker };
264*1783903dSAndroid Build Coastguard Worker
265*1783903dSAndroid Build Coastguard Worker DEFINE_BPF_PROG("tracepoint/sched/sched_process_free", AID_ROOT, AID_SYSTEM,
266*1783903dSAndroid Build Coastguard Worker tracepoint_sched_sched_process_free)
267*1783903dSAndroid Build Coastguard Worker (struct sched_process_free_args* args) {
268*1783903dSAndroid Build Coastguard Worker const int ALLOW = 1;
269*1783903dSAndroid Build Coastguard Worker
270*1783903dSAndroid Build Coastguard Worker int pid = args->pid;
271*1783903dSAndroid Build Coastguard Worker bool is_last = true;
272*1783903dSAndroid Build Coastguard Worker
273*1783903dSAndroid Build Coastguard Worker // eBPF verifier does not currently allow loops.
274*1783903dSAndroid Build Coastguard Worker // Instruct the C compiler to unroll the loop into a series of steps.
275*1783903dSAndroid Build Coastguard Worker #pragma unroll
276*1783903dSAndroid Build Coastguard Worker for (uint32_t index = 0; index < MAX_TRACKED_PIDS; index++) {
277*1783903dSAndroid Build Coastguard Worker const uint32_t key = MAX_TRACKED_PIDS - index - 1;
278*1783903dSAndroid Build Coastguard Worker tracked_pid_t* tracked_pid = bpf_pid_tracked_map_lookup_elem(&key);
279*1783903dSAndroid Build Coastguard Worker if (!tracked_pid) continue;
280*1783903dSAndroid Build Coastguard Worker if (tracked_pid->pid == pid) {
281*1783903dSAndroid Build Coastguard Worker tracked_pid->pid = 0;
282*1783903dSAndroid Build Coastguard Worker tracked_pid->state = is_last ? TRACKED_PID_STATE_UNUSED : TRACKED_PID_STATE_EXITED;
283*1783903dSAndroid Build Coastguard Worker bpf_pid_tracked_hash_map_delete_elem(&key);
284*1783903dSAndroid Build Coastguard Worker break;
285*1783903dSAndroid Build Coastguard Worker }
286*1783903dSAndroid Build Coastguard Worker if (tracked_pid->state == TRACKED_PID_STATE_ACTIVE) {
287*1783903dSAndroid Build Coastguard Worker is_last = false;
288*1783903dSAndroid Build Coastguard Worker }
289*1783903dSAndroid Build Coastguard Worker }
290*1783903dSAndroid Build Coastguard Worker
291*1783903dSAndroid Build Coastguard Worker bpf_pid_task_aggregation_map_delete_elem(&pid);
292*1783903dSAndroid Build Coastguard Worker return ALLOW;
293*1783903dSAndroid Build Coastguard Worker }
294*1783903dSAndroid Build Coastguard Worker
295*1783903dSAndroid Build Coastguard Worker LICENSE("GPL");
296