private static final ThreadFactory sDBThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(@NonNull Runnable r) {
WorkerRunnable wr = new WorkerRunnable(r, Process.THREAD_PRIORITY_BACKGROUND);
return new Thread(wr, "Async DB Thread #" + mCount.getAndIncrement());
}
};
private static class WorkerRunnable implements Runnable {
Runnable runnable;
int priority;
String tag;
public WorkerRunnable(Runnable runnable, int priority) {
this(runnable, priority, "WorkerRunnable");
}
public WorkerRunnable(Runnable runnable, int priority, String tag) {
this.runnable = runnable;
this.priority = priority;
this.tag = tag;
}
@Override
public void run() {
android.os.Process.setThreadPriority(priority);
runnable.run();
}
@Override
public String toString() {
return tag + ":" + runnable;
}
}
在Android5.1.0中当线程优先级为Process.THREAD_PRIORITY_BACKGROUND的Async DB Thread所属的进程处于前台时,其cgroup却为fg,当所属进程进入到后台时,其cgroup又为bg:
int get_sched_policy(int tid, SchedPolicy *policy)
{
#ifdef HAVE_GETTID
if (tid == 0) {
tid = gettid();
}
#endif
pthread_once(&the_once, __initialize);
if (__sys_supports_schedgroups) {
char grpBuf[32];
if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
return -1;
if (grpBuf[0] == '\0') {
*policy = SP_SYSTEM;
} else if (!strcmp(grpBuf, "apps/bg_non_interactive")) {
*policy = SP_BACKGROUND;
} else if (!strcmp(grpBuf, "apps")) {
*policy = SP_FOREGROUND;
} else {
errno = ERANGE;
return -1;
}
} else {
int rc = sched_getscheduler(tid);
if (rc < 0)
return -1;
else if (rc == SCHED_NORMAL)
*policy = SP_FOREGROUND;
else if (rc == SCHED_BATCH)
*policy = SP_BACKGROUND;
else {
errno = ERANGE;
return -1;
}
}
return 0;
}
上述代码基本逻辑概要如下:
if (!access("/dev/cpuctl/tasks", F_OK)) {
__sys_supports_schedgroups = 1;
}
也就是查看/dev/cpuctl/tasks是否存在:当/dev/cpuctl/tasks存在时,access返回0,满足条件__sys_supports_schedgroups为1。
sched_setscheduler(tid, (policy == SP_BACKGROUND) ? SCHED_BATCH : SCHED_NORMAL, ¶m);
而sched_setscheduler则是由set_sched_policy调用:
if (gDoSchedulingGroup) {
if (prio >= ANDROID_PRIORITY_BACKGROUND) {
set_sched_policy(androidGetTid(), SP_BACKGROUND);
} else if (prio > ANDROID_PRIORITY_AUDIO) {
set_sched_policy(androidGetTid(), SP_FOREGROUND);
} else {
// defaults to that of parent, or as set by requestPriority()
}
}
本文来自网易实践者社区,经作者冯越新授权发布。