Linux系统将进程分为实时进程和普通进程,实时进程的优先级范围为0~99,普通进程为100~139,并且二者的调度策略也是不通的。Android系统是基于Linux系统之上开发的,其充分利用了Linux系统的一些特性,有些甚至可以做为开发范本。这篇文章分析一下Android系统是如何利用Linux进程调度策略来管理进程优先级的,源码参考Android 9.0。
实时进程
Android中对实时进程使用了SCHED_FIFO策略,这个策略使用先进先出的管理规则,进程占有CPU时,如果没有更高优先级的实时进程抢占或主动让出,进程将保持使用CPU。这也说明Android系统希望实时进程能高优先级的持续运行,不想其因为时间片的耗尽而中断执行。但系统是不会让实时进程一直运行的,CPU消耗型的进程是不会设置为实时进程的,实时进程更倾向于为实时性较为敏感的IO消耗型进程服务。
Android系统在以下几个地方设置了SCHED_FIFO调度策略,
AMS中,当属性"sys.use_fifo_ui"设置为1时,将前台进程的UI线程和Render线程设置为为实时策略,否则为普通进程。同时设置了SCHED_RESET_ON_FORK位,表明其子进程会恢复默认的调度策略。
Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
SurfaceFlinger中,在亮屏时使用实时调度,灭屏时使用非实时调度。
sched_setscheduler(0, SCHED_FIFO, ¶m)
如果支持Audio FastMixer,FastMixer使用实时调度,通过requestPriority()设置。
Android新增加的AAudioService中,将client线程设置为实时策略,通过requestPriority()设置。
属性"camera.fifo.disable"没有被设置时,将Cameraservice的request线程设置为实时策略,通过requestPriority()设置。
Audio HIDL使用实时策略,通过requestPriority()设置。
frameworks/base/services/core/java/com/android/server/os/SchedulingPolicyService.java 83 public int requestPriority(int pid, int tid, int prio, boolean isForApp) { ...... // UID为AudioServer,CameraServer,Bluetooth时才能使用该接口, // 优先级为1~3,线程组ID(tgid)与pid不同时不能使用该接口92 if (!isPermitted() || prio < PRIORITY_MIN ||93 prio > PRIORITY_MAX || Process.getThreadGroupLeader(tid) != pid) {94 return PackageManager.PERMISSION_DENIED;95 } // 非Bluetooth时,App设置到THREAD_GROUP_RT_APP,非App设置到THREAD_GROUP_AUDIO_SYS96 if (Binder.getCallingUid() != Process.BLUETOOTH_UID) {97 try {98 // make good use of our CAP_SYS_NICE capability99 Process.setThreadGroup(tid, !isForApp ?100 Process.THREAD_GROUP_AUDIO_SYS : Process.THREAD_GROUP_RT_APP);101 } catch (RuntimeException e) { ......104 }105 }106 try {107 // must be in this order or it fails the schedulability constraint108 Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK,109 prio);110 } catch (RuntimeException e) { ......113 }114 return PackageManager.PERMISSION_GRANTED;115 }
可以看出Android对实时调度策略的使用是很谨慎的,只有与硬件相关的数据传输进程才会使用实时策略。大部分的进程还是做为普通进程通过优先级的调整来管理。
普通进程
Android中的普通进程使用SCHED_OTHER调度策略,它将普通进程的优先级化为9个级别。
frameworks/base/core/java/android/os/Process.java // 默认优先级225 public static final int THREAD_PRIORITY_DEFAULT = 0; // 最低优先级240 public static final int THREAD_PRIORITY_LOWEST = 19; // 后台线程优先级,略低于默认优先级,可以减少对用户交互的影响250 public