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; |