blob: 5cbe1a1e9816fd01b43e3f3949ff5f2432f00f59 [file] [log] [blame]
Glenn Kasten07b04652012-04-23 15:00:43 -07001/*
2 * Copyright (C) 2012 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
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.os;
Glenn Kasten07b04652012-04-23 15:00:43 -070018
Glenn Kasten07b04652012-04-23 15:00:43 -070019import android.content.pm.PackageManager;
20import android.os.Binder;
Chong Zhang37520f02018-04-13 10:31:44 -070021import android.os.IBinder;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080022import android.os.ISchedulingPolicyService;
Glenn Kasten07b04652012-04-23 15:00:43 -070023import android.os.Process;
Chong Zhang37520f02018-04-13 10:31:44 -070024import android.os.RemoteException;
Philip Cuadra41950492017-03-24 14:09:19 -070025import android.util.Log;
Glenn Kasten07b04652012-04-23 15:00:43 -070026
Chong Zhang779df802018-04-20 17:09:14 -070027import com.android.server.SystemServerInitThreadPool;
28
Glenn Kasten07b04652012-04-23 15:00:43 -070029/**
30 * The implementation of the scheduling policy service interface.
31 *
32 * @hide
33 */
34public class SchedulingPolicyService extends ISchedulingPolicyService.Stub {
35
36 private static final String TAG = "SchedulingPolicyService";
37
38 // Minimum and maximum values allowed for requestPriority parameter prio
39 private static final int PRIORITY_MIN = 1;
Glenn Kasten430c2542012-06-04 11:42:01 -070040 private static final int PRIORITY_MAX = 3;
Glenn Kasten07b04652012-04-23 15:00:43 -070041
Chong Zhang37520f02018-04-13 10:31:44 -070042 private static final String[] MEDIA_PROCESS_NAMES = new String[] {
43 "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
44 };
45 private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
46 @Override
47 public void binderDied() {
48 requestCpusetBoost(false /*enable*/, null /*client*/);
49 }
50 };
51 // Current process that received a cpuset boost
52 private int mBoostedPid = -1;
53 // Current client registered to the death recipient
54 private IBinder mClient;
55
Glenn Kasten07b04652012-04-23 15:00:43 -070056 public SchedulingPolicyService() {
Chong Zhang37520f02018-04-13 10:31:44 -070057 // system_server (our host) could have crashed before. The app may not survive
58 // it, but mediaserver/media.codec could have, and mediaserver probably tried
59 // to disable the boost while we were dead.
60 // We do a restore of media.codec to default cpuset upon service restart to
61 // catch this case. We can't leave media.codec in boosted state, because we've
62 // lost the death recipient of mClient from mediaserver after the restart,
63 // if mediaserver dies in the future we won't have a notification to reset.
64 // (Note that if mediaserver thinks we're in boosted state before the crash,
65 // the state could go out of sync temporarily until mediaserver enables/disable
66 // boost next time, but this won't be a big issue.)
Chong Zhang779df802018-04-20 17:09:14 -070067 SystemServerInitThreadPool.get().submit(() -> {
68 synchronized (mDeathRecipient) {
69 // only do this if we haven't already got a request to boost.
70 if (mBoostedPid == -1) {
71 int[] nativePids = Process.getPidsForCommands(MEDIA_PROCESS_NAMES);
72 if (nativePids != null && nativePids.length == 1) {
73 mBoostedPid = nativePids[0];
74 disableCpusetBoost(nativePids[0]);
75 }
76 }
77 }
78 }, TAG + ".<init>");
Glenn Kasten07b04652012-04-23 15:00:43 -070079 }
80
Mikhail Naganova0cb18d2017-02-07 10:50:21 -080081 // TODO(b/35196900) We should pass the period in time units, rather
82 // than a fixed priority number.
83 public int requestPriority(int pid, int tid, int prio, boolean isForApp) {
Glenn Kasten07b04652012-04-23 15:00:43 -070084 //Log.i(TAG, "requestPriority(pid=" + pid + ", tid=" + tid + ", prio=" + prio + ")");
85
Andy Hunged0ea402015-10-30 14:11:46 -070086 // Verify that the caller uid is permitted, priority is in range,
87 // and that the callback thread specified by app belongs to the app that
88 // called mediaserver or audioserver.
89 // Once we've verified that the caller uid is permitted, we can trust the pid but
Glenn Kasten07b04652012-04-23 15:00:43 -070090 // we can't trust the tid. No need to explicitly check for pid == 0 || tid == 0,
91 // since if not the case then the getThreadGroupLeader() test will also fail.
Steven Moreland3d8166f2017-04-07 10:47:06 -070092 if (!isPermitted() || prio < PRIORITY_MIN ||
Glenn Kasten07b04652012-04-23 15:00:43 -070093 prio > PRIORITY_MAX || Process.getThreadGroupLeader(tid) != pid) {
Philip Cuadra41950492017-03-24 14:09:19 -070094 return PackageManager.PERMISSION_DENIED;
95 }
96 if (Binder.getCallingUid() != Process.BLUETOOTH_UID) {
97 try {
98 // make good use of our CAP_SYS_NICE capability
99 Process.setThreadGroup(tid, !isForApp ?
Glenn Kasten9a3f9532017-04-20 14:49:16 -0700100 Process.THREAD_GROUP_AUDIO_SYS : Process.THREAD_GROUP_RT_APP);
Philip Cuadra41950492017-03-24 14:09:19 -0700101 } catch (RuntimeException e) {
102 Log.e(TAG, "Failed setThreadGroup: " + e);
103 return PackageManager.PERMISSION_DENIED;
104 }
Glenn Kasten07b04652012-04-23 15:00:43 -0700105 }
106 try {
Glenn Kasten07b04652012-04-23 15:00:43 -0700107 // must be in this order or it fails the schedulability constraint
Tim Murray38ee3372016-08-18 11:13:26 -0700108 Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK,
Philip Cuadra41950492017-03-24 14:09:19 -0700109 prio);
Glenn Kasten07b04652012-04-23 15:00:43 -0700110 } catch (RuntimeException e) {
Philip Cuadra41950492017-03-24 14:09:19 -0700111 Log.e(TAG, "Failed setThreadScheduler: " + e);
Glenn Kasten07b04652012-04-23 15:00:43 -0700112 return PackageManager.PERMISSION_DENIED;
113 }
114 return PackageManager.PERMISSION_GRANTED;
115 }
116
Chong Zhang37520f02018-04-13 10:31:44 -0700117 // Request to move media.codec process between SP_FOREGROUND and SP_TOP_APP.
118 public int requestCpusetBoost(boolean enable, IBinder client) {
Chong Zhang779df802018-04-20 17:09:14 -0700119 // Can only allow mediaserver to call this.
120 if (Binder.getCallingPid() != Process.myPid() &&
121 Binder.getCallingUid() != Process.MEDIA_UID) {
Chong Zhang37520f02018-04-13 10:31:44 -0700122 return PackageManager.PERMISSION_DENIED;
123 }
124
125 int[] nativePids = Process.getPidsForCommands(MEDIA_PROCESS_NAMES);
126 if (nativePids == null || nativePids.length != 1) {
127 Log.e(TAG, "requestCpusetBoost: can't find media.codec process");
128 return PackageManager.PERMISSION_DENIED;
129 }
130
131 synchronized (mDeathRecipient) {
132 if (enable) {
133 return enableCpusetBoost(nativePids[0], client);
134 } else {
135 return disableCpusetBoost(nativePids[0]);
136 }
137 }
138 }
139
140 private int enableCpusetBoost(int pid, IBinder client) {
141 if (mBoostedPid == pid) {
142 return PackageManager.PERMISSION_GRANTED;
143 }
144
145 // The mediacodec process has changed, clean up the old pid and
146 // client before we boost the new process, so that the state
147 // is left clean if things go wrong.
148 mBoostedPid = -1;
149 if (mClient != null) {
150 try {
151 mClient.unlinkToDeath(mDeathRecipient, 0);
152 } catch (Exception e) {
153 } finally {
154 mClient = null;
155 }
156 }
157
158 try {
159 client.linkToDeath(mDeathRecipient, 0);
160
161 Log.i(TAG, "Moving " + pid + " to group " + Process.THREAD_GROUP_TOP_APP);
162 Process.setProcessGroup(pid, Process.THREAD_GROUP_TOP_APP);
163
164 mBoostedPid = pid;
165 mClient = client;
166
167 return PackageManager.PERMISSION_GRANTED;
168 } catch (Exception e) {
169 Log.e(TAG, "Failed enableCpusetBoost: " + e);
170 try {
171 // unlink if things go wrong and don't crash.
172 client.unlinkToDeath(mDeathRecipient, 0);
173 } catch (Exception e1) {}
174 }
175
176 return PackageManager.PERMISSION_DENIED;
177 }
178
179 private int disableCpusetBoost(int pid) {
180 int boostedPid = mBoostedPid;
181
182 // Clean up states first.
183 mBoostedPid = -1;
184 if (mClient != null) {
185 try {
186 mClient.unlinkToDeath(mDeathRecipient, 0);
187 } catch (Exception e) {
188 } finally {
189 mClient = null;
190 }
191 }
192
193 // Try restore the old thread group, no need to fail as the
194 // mediacodec process could be dead just now.
195 if (boostedPid == pid) {
196 try {
197 Log.i(TAG, "Moving " + pid + " back to group default");
198 Process.setProcessGroup(pid, Process.THREAD_GROUP_DEFAULT);
199 } catch (Exception e) {
200 Log.w(TAG, "Couldn't move pid " + pid + " back to group default");
201 }
202 }
203
204 return PackageManager.PERMISSION_GRANTED;
205 }
206
Steven Moreland3d8166f2017-04-07 10:47:06 -0700207 private boolean isPermitted() {
208 // schedulerservice hidl
209 if (Binder.getCallingPid() == Process.myPid()) {
210 return true;
211 }
212
213 switch (Binder.getCallingUid()) {
Chong Zhang37520f02018-04-13 10:31:44 -0700214 case Process.AUDIOSERVER_UID: // fastcapture, fastmixer
Eino-Ville Talvala1f677fd2016-04-25 17:05:03 -0700215 case Process.CAMERASERVER_UID: // camera high frame rate recording
Chong Zhang37520f02018-04-13 10:31:44 -0700216 case Process.BLUETOOTH_UID: // Bluetooth audio playback
Andy Hunged0ea402015-10-30 14:11:46 -0700217 return true;
218 default:
219 return false;
220 }
221 }
Glenn Kasten07b04652012-04-23 15:00:43 -0700222}