aboutsummaryrefslogtreecommitdiff
path: root/include/linux/im/im.c
blob: cf68cc3021e1073b3661c8c6569057cf6d683673 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include <linux/im/im.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/kernel.h>
#include <linux/module.h>

/* default list, empty string means no need to check */
static struct im_target {
	char val[64];
	const char* desc;
} im_target [IM_ID_MAX] = {
	{"surfaceflinger", "sf "},
	{"", "kworker "},
	{"logd", "logd "},
	{"logcat", "logcat "},
	{"", "main "},
	{"", "enqueue "},
	{"", "gl "},
	{"", "vk "},
	{"composer-servic", "hwc "},
	{"HwBinder:", "hwbinder "},
	{"Binder:", "binder "},
	{"hwuiTask", "hwui "},
	{"", "render "},
	{"", "unity_wk"},
	{"UnityMain", "unityM"},
	{"neplus.launcher", "launcher "},
	{"HwuiTask", "HwuiEx "},
	{"CrRendererMain", "crender "},
};

/* ignore list, not set any im_flag */
static char target_ignore_prefix[IM_IG_MAX][64] = {
	"Prober_",
	"DispSync",
	"app",
	"sf",
	"ScreenShotThrea",
	"DPPS_THREAD",
	"LTM_THREAD",
};

void im_to_str(int flag, char* desc, int size)
{
	char *base = desc;
	int i;

	for (i = 0; i < IM_ID_MAX; ++i) {
		if (flag & (1 << i)) {
			size_t len = strlen(im_target[i].desc);

			if (len) {
				if (size <= base - desc + len) {
					pr_warn("im tag desc too long\n");
					return;
				}
				strncpy(base, im_target[i].desc, len);
				base += len;
			}
		}
	}
}

static inline bool im_ignore(struct task_struct *task, int idx)
{
	size_t tlen = 0, len = 0;

	tlen = strlen(target_ignore_prefix[idx]);
	if (tlen == 0)
		return false;

	/* NOTE: task->comm has only 16 bytes */
	len = strlen(task->comm);
	if (len < tlen)
		return false;

	if (!strncmp(task->comm, target_ignore_prefix[idx], tlen)) {
		task->im_flag = 0;
		return true;
	}
	return false;
}

static inline void im_tagging(struct task_struct *task, int idx)
{
	size_t tlen = 0, len = 0;

	tlen = strlen(im_target[idx].val);
	if (tlen == 0)
		return;

	/* NOTE: task->comm has only 16 bytes */
	len = strlen(task->comm);

	/* non restrict tagging for some prefixed tasks*/
	if (len < tlen)
		return;

	/* prefix cases */
	if (!strncmp(task->comm, im_target[idx].val, tlen)) {
		switch (idx) {
		case IM_ID_HWBINDER:
			task->im_flag |= IM_HWBINDER;
			break;
		case IM_ID_BINDER:
			task->im_flag |= IM_BINDER;
			break;
		case IM_ID_HWUI:
			task->im_flag |= IM_HWUI;
			break;
		case IM_ID_HWUI_EX:
			task->im_flag |= IM_HWUI_EX;
			break;
		}
	}

	/* restrict tagging for specific identical tasks */
	if (len != tlen)
		return;

	if (!strncmp(task->comm, im_target[idx].val, len)) {
		switch (idx) {
		case IM_ID_SURFACEFLINGER:
			task->im_flag |= IM_SURFACEFLINGER;
			break;
		case IM_ID_LOGD:
			task->im_flag |= IM_LOGD;
			break;
		case IM_ID_LOGCAT:
			task->im_flag |= IM_LOGCAT;
			break;
		case IM_ID_HWC:
			task->im_flag |= IM_HWC;
			break;
		case IM_ID_LAUNCHER:
			task->im_flag |= IM_LAUNCHER;
			break;
		case IM_ID_RENDER:
			task->im_flag |= IM_RENDER;
			break;
		case IM_ID_UNITY_MAIN:
			task->im_flag |= IM_UNITY_MAIN;
			break;
		}
	}
}

void im_wmi(struct task_struct *task)
{
	struct task_struct *leader = task, *p;
	int i = 0;

	/* check for ignore */
	for (i = 0; i < IM_IG_MAX; ++i)
		if (im_ignore(task, i))
			return;

	/* do the check and initial */
	task->im_flag = 0;
	for (i = 0; i < IM_ID_MAX; ++i)
		im_tagging(task, i);

	/* check leader part */
	rcu_read_lock();
	if (task != task->group_leader)
		leader = find_task_by_vpid(task->tgid);

	if (leader) {
		/* for hwc cases */
		if (im_hwc(leader)) {
			for_each_thread(task, p) {
				if (im_binder_related(p))
					p->im_flag |= IM_HWC;
			}
		}

		/* for sf cases */
		if (im_sf(leader) && im_binder_related(task))
			task->im_flag |= IM_SURFACEFLINGER;
	}
	rcu_read_unlock();
}

void im_set_flag(struct task_struct *task, int flag)
{
	/* for hwui boost purpose */
	im_tagging(current, IM_ID_HWUI);
	if (current->im_flag & IM_HWUI)
		return;

	im_tagging(current, IM_ID_HWUI_EX);
	if (current->im_flag & IM_HWUI_EX)
		return;

	/* set the flag */
	current->im_flag |= flag;

	/* if task with enqueue operation, then it's leader should be main thread */
	if (flag == IM_ENQUEUE) {
		struct task_struct *leader = current;

		rcu_read_lock();
		/* refetch leader */
		if (current != current->group_leader)
			leader = find_task_by_vpid(current->tgid);
		if (leader)
			leader->im_flag |= IM_MAIN;
		rcu_read_unlock();
	}
}

void im_unset_flag(struct task_struct *task, int flag)
{
	task->im_flag &= ~flag;
}

void im_reset_flag(struct task_struct *task)
{
	task->im_flag = 0;
}

void im_tsk_init_flag(void *ptr)
{
	struct task_struct *task = (struct task_struct*) ptr;

	task->im_flag &= ~(IM_HWUI & IM_HWUI_EX);
}