diff options
| -rw-r--r-- | core/java/android/os/ISchedulingPolicyService.aidl | 9 | ||||
| -rw-r--r-- | services/core/java/com/android/server/os/SchedulingPolicyService.java | 124 |
2 files changed, 131 insertions, 2 deletions
diff --git a/core/java/android/os/ISchedulingPolicyService.aidl b/core/java/android/os/ISchedulingPolicyService.aidl index efcf59aaa661..78d299af13eb 100644 --- a/core/java/android/os/ISchedulingPolicyService.aidl +++ b/core/java/android/os/ISchedulingPolicyService.aidl @@ -31,4 +31,13 @@ interface ISchedulingPolicyService { */ int requestPriority(int pid, int tid, int prio, boolean isForApp); + /** + * Move media.codec process between SP_FOREGROUND and SP_TOP_APP. + * When 'enable' is 'true', server will attempt to move media.codec process + * from SP_FOREGROUND into SP_TOP_APP cpuset. A valid 'client' must be + * provided for the server to receive death notifications. When 'enable' + * is 'false', server will attempt to move media.codec process back to + * the original cpuset, and 'client' is ignored in this case. + */ + int requestCpusetBoost(boolean enable, IBinder client); } diff --git a/services/core/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java index e0b8426a56d2..c64e745a3ac2 100644 --- a/services/core/java/com/android/server/os/SchedulingPolicyService.java +++ b/services/core/java/com/android/server/os/SchedulingPolicyService.java @@ -18,8 +18,10 @@ package com.android.server.os; import android.content.pm.PackageManager; import android.os.Binder; +import android.os.IBinder; import android.os.ISchedulingPolicyService; import android.os.Process; +import android.os.RemoteException; import android.util.Log; /** @@ -35,7 +37,36 @@ public class SchedulingPolicyService extends ISchedulingPolicyService.Stub { private static final int PRIORITY_MIN = 1; private static final int PRIORITY_MAX = 3; + private static final String[] MEDIA_PROCESS_NAMES = new String[] { + "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service + }; + private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + requestCpusetBoost(false /*enable*/, null /*client*/); + } + }; + // Current process that received a cpuset boost + private int mBoostedPid = -1; + // Current client registered to the death recipient + private IBinder mClient; + public SchedulingPolicyService() { + // system_server (our host) could have crashed before. The app may not survive + // it, but mediaserver/media.codec could have, and mediaserver probably tried + // to disable the boost while we were dead. + // We do a restore of media.codec to default cpuset upon service restart to + // catch this case. We can't leave media.codec in boosted state, because we've + // lost the death recipient of mClient from mediaserver after the restart, + // if mediaserver dies in the future we won't have a notification to reset. + // (Note that if mediaserver thinks we're in boosted state before the crash, + // the state could go out of sync temporarily until mediaserver enables/disable + // boost next time, but this won't be a big issue.) + int[] nativePids = Process.getPidsForCommands(MEDIA_PROCESS_NAMES); + if (nativePids != null && nativePids.length == 1) { + mBoostedPid = nativePids[0]; + disableCpusetBoost(nativePids[0]); + } } // TODO(b/35196900) We should pass the period in time units, rather @@ -74,6 +105,94 @@ public class SchedulingPolicyService extends ISchedulingPolicyService.Stub { return PackageManager.PERMISSION_GRANTED; } + // Request to move media.codec process between SP_FOREGROUND and SP_TOP_APP. + public int requestCpusetBoost(boolean enable, IBinder client) { + if (!isPermitted()) { + return PackageManager.PERMISSION_DENIED; + } + + int[] nativePids = Process.getPidsForCommands(MEDIA_PROCESS_NAMES); + if (nativePids == null || nativePids.length != 1) { + Log.e(TAG, "requestCpusetBoost: can't find media.codec process"); + return PackageManager.PERMISSION_DENIED; + } + + synchronized (mDeathRecipient) { + if (enable) { + return enableCpusetBoost(nativePids[0], client); + } else { + return disableCpusetBoost(nativePids[0]); + } + } + } + + private int enableCpusetBoost(int pid, IBinder client) { + if (mBoostedPid == pid) { + return PackageManager.PERMISSION_GRANTED; + } + + // The mediacodec process has changed, clean up the old pid and + // client before we boost the new process, so that the state + // is left clean if things go wrong. + mBoostedPid = -1; + if (mClient != null) { + try { + mClient.unlinkToDeath(mDeathRecipient, 0); + } catch (Exception e) { + } finally { + mClient = null; + } + } + + try { + client.linkToDeath(mDeathRecipient, 0); + + Log.i(TAG, "Moving " + pid + " to group " + Process.THREAD_GROUP_TOP_APP); + Process.setProcessGroup(pid, Process.THREAD_GROUP_TOP_APP); + + mBoostedPid = pid; + mClient = client; + + return PackageManager.PERMISSION_GRANTED; + } catch (Exception e) { + Log.e(TAG, "Failed enableCpusetBoost: " + e); + try { + // unlink if things go wrong and don't crash. + client.unlinkToDeath(mDeathRecipient, 0); + } catch (Exception e1) {} + } + + return PackageManager.PERMISSION_DENIED; + } + + private int disableCpusetBoost(int pid) { + int boostedPid = mBoostedPid; + + // Clean up states first. + mBoostedPid = -1; + if (mClient != null) { + try { + mClient.unlinkToDeath(mDeathRecipient, 0); + } catch (Exception e) { + } finally { + mClient = null; + } + } + + // Try restore the old thread group, no need to fail as the + // mediacodec process could be dead just now. + if (boostedPid == pid) { + try { + Log.i(TAG, "Moving " + pid + " back to group default"); + Process.setProcessGroup(pid, Process.THREAD_GROUP_DEFAULT); + } catch (Exception e) { + Log.w(TAG, "Couldn't move pid " + pid + " back to group default"); + } + } + + return PackageManager.PERMISSION_GRANTED; + } + private boolean isPermitted() { // schedulerservice hidl if (Binder.getCallingPid() == Process.myPid()) { @@ -81,9 +200,10 @@ public class SchedulingPolicyService extends ISchedulingPolicyService.Stub { } switch (Binder.getCallingUid()) { - case Process.AUDIOSERVER_UID: // fastcapture, fastmixer + case Process.AUDIOSERVER_UID: // fastcapture, fastmixer + case Process.MEDIA_UID: // mediaserver case Process.CAMERASERVER_UID: // camera high frame rate recording - case Process.BLUETOOTH_UID: // Bluetooth audio playback + case Process.BLUETOOTH_UID: // Bluetooth audio playback return true; default: return false; |