Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 37520f0e authored by Chong Zhang's avatar Chong Zhang
Browse files

Adjust media.codec process group upon request from mediaserver

Add method to allow dynamic adjustment of cpuset of media.codec
process. Only accept requests coming from mediaserver.

Bug: 72841545

Change-Id: Idb09d9a5162691503ecf6d811a528d9160326358
parent 61ac5728
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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);
}
+122 −2
Original line number Diff line number Diff line
@@ -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()) {
@@ -82,6 +201,7 @@ public class SchedulingPolicyService extends ISchedulingPolicyService.Stub {

        switch (Binder.getCallingUid()) {
        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
            return true;