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

Commit 8c6cedc9 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Propagate background scheduling class across processes.

This is a very simply implementation: upon receiving an IPC, if the handling
thread is at a background priority (the driver will have taken care of
propagating this from the calling thread), then stick it in to the background
scheduling group.  Plus an API to turn this off for the process, which is
used by the system process.

This also pulls some of the code for managing scheduling classes out of
the Process JNI wrappers and in to some convenience methods in thread.h.
parent d56352bd
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -52,7 +52,7 @@ public:
        DUMP_TRANSACTION        = B_PACK_CHARS('_','D','M','P'),
        DUMP_TRANSACTION        = B_PACK_CHARS('_','D','M','P'),
        INTERFACE_TRANSACTION   = B_PACK_CHARS('_', 'N', 'T', 'F'),
        INTERFACE_TRANSACTION   = B_PACK_CHARS('_', 'N', 'T', 'F'),


        // Corresponds to tfOneWay -- an asynchronous call.
        // Corresponds to TF_ONE_WAY -- an asynchronous call.
        FLAG_ONEWAY             = 0x00000001
        FLAG_ONEWAY             = 0x00000001
    };
    };


+9 −1
Original line number Original line Diff line number Diff line
@@ -68,6 +68,13 @@ public:


    static  void                shutdown();
    static  void                shutdown();
    
    
    // Call this to disable switching threads to background scheduling when
    // receiving incoming IPC calls.  This is specifically here for the
    // Android system process, since it expects to have background apps calling
    // in to it but doesn't want to acquire locks in its services while in
    // the background.
    static  void                disableBackgroundScheduling(bool disable);
    
private:
private:
                                IPCThreadState();
                                IPCThreadState();
                                ~IPCThreadState();
                                ~IPCThreadState();
@@ -93,6 +100,7 @@ private:
                                           void* cookie);
                                           void* cookie);
    
    
    const   sp<ProcessState>    mProcess;
    const   sp<ProcessState>    mProcess;
    const   pid_t               mMyThreadId;
            Vector<BBinder*>    mPendingStrongDerefs;
            Vector<BBinder*>    mPendingStrongDerefs;
            Vector<RefBase::weakref_type*> mPendingWeakDerefs;
            Vector<RefBase::weakref_type*> mPendingWeakDerefs;
            
            
+18 −0
Original line number Original line Diff line number Diff line
@@ -124,6 +124,24 @@ typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,


extern void androidSetCreateThreadFunc(android_create_thread_fn func);
extern void androidSetCreateThreadFunc(android_create_thread_fn func);


// ------------------------------------------------------------------
// Extra functions working with raw pids.

// Get pid for the current thread.
extern pid_t androidGetTid();

// Change the scheduling group of a particular thread.  The group
// should be one of the ANDROID_TGROUP constants.  Returns BAD_VALUE if
// grp is out of range, else another non-zero value with errno set if
// the operation failed.
extern int androidSetThreadSchedulingGroup(pid_t tid, int grp);

// Change the priority AND scheduling group of a particular thread.  The priority
// should be one of the ANDROID_PRIORITY constants.  Returns INVALID_OPERATION
// if the priority set failed, else another value if just the group set failed;
// in either case errno is set.
extern int androidSetThreadPriority(pid_t tid, int prio);

#ifdef __cplusplus
#ifdef __cplusplus
}
}
#endif
#endif
+38 −15
Original line number Original line Diff line number Diff line
@@ -292,6 +292,7 @@ static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static bool gHaveTLS = false;
static pthread_key_t gTLS = 0;
static pthread_key_t gTLS = 0;
static bool gShutdown = false;
static bool gShutdown = false;
static bool gDisableBackgroundScheduling = false;


IPCThreadState* IPCThreadState::self()
IPCThreadState* IPCThreadState::self()
{
{
@@ -332,6 +333,11 @@ void IPCThreadState::shutdown()
    }
    }
}
}


void IPCThreadState::disableBackgroundScheduling(bool disable)
{
    gDisableBackgroundScheduling = disable;
}

sp<ProcessState> IPCThreadState::process()
sp<ProcessState> IPCThreadState::process()
{
{
    return mProcess;
    return mProcess;
@@ -386,6 +392,11 @@ void IPCThreadState::joinThreadPool(bool isMain)


    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    
    
    // This thread may have been spawned by a thread that was in the background
    // scheduling group, so first we will make sure it is in the default/foreground
    // one to avoid performing an initial transaction in the background.
    androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
        
    status_t result;
    status_t result;
    do {
    do {
        int32_t cmd;
        int32_t cmd;
@@ -427,19 +438,13 @@ void IPCThreadState::joinThreadPool(bool isMain)
        }
        }
        
        
        // After executing the command, ensure that the thread is returned to the
        // After executing the command, ensure that the thread is returned to the
        // default cgroup and priority before rejoining the pool.  This is a failsafe
        // default cgroup before rejoining the pool.  The driver takes care of
        // in case the command implementation failed to properly restore the thread's
        // restoring the priority, but doesn't do anything with cgroups so we
        // scheduling parameters upon completion.
        // need to take care of that here in userspace.  Note that we do make
        int my_id;
        // sure to go in the foreground after executing a transaction, but
#ifdef HAVE_GETTID
        // there are other callbacks into user code that could have changed
        my_id = gettid();
        // our group so we want to make absolutely sure it is put back.
#else
        androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
        my_id = getpid();
#endif
        if (!set_sched_policy(my_id, SP_FOREGROUND)) {
            // success; reset the priority as well
            setpriority(PRIO_PROCESS, my_id, ANDROID_PRIORITY_NORMAL);
        }


        // Let this thread exit the thread pool if it is no longer
        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        // needed and it is not the main process thread.
@@ -583,7 +588,7 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
}
}


IPCThreadState::IPCThreadState()
IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self())
    : mProcess(ProcessState::self()), mMyThreadId(androidGetTid())
{
{
    pthread_setspecific(gTLS, this);
    pthread_setspecific(gTLS, this);
    clearCaller();
    clearCaller();
@@ -930,6 +935,17 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
            mCallingPid = tr.sender_pid;
            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            mCallingUid = tr.sender_euid;
            
            
            bool doBackground = !gDisableBackgroundScheduling &&
                    getpriority(PRIO_PROCESS, mMyThreadId)
                            >= ANDROID_PRIORITY_BACKGROUND;
            if (doBackground) {
                // We have inherited a background priority from the caller.
                // Ensure this thread is in the background scheduling class,
                // since the driver won't modify scheduling classes for us.
                androidSetThreadSchedulingGroup(mMyThreadId,
                        ANDROID_TGROUP_BG_NONINTERACT);
            }
            
            //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
            //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
            
            
            Parcel reply;
            Parcel reply;
@@ -967,6 +983,13 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
            mCallingPid = origPid;
            mCallingPid = origPid;
            mCallingUid = origUid;
            mCallingUid = origUid;
            
            
            if (doBackground) {
                // We moved to the background scheduling group to execute
                // this transaction, so now that we are done go back in the
                // foreground.
                androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
            }
            
            IF_LOG_TRANSACTIONS() {
            IF_LOG_TRANSACTIONS() {
                TextOutput::Bundle _b(alog);
                TextOutput::Bundle _b(alog);
                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
+49 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@
#include <utils/threads.h>
#include <utils/threads.h>
#include <utils/Log.h>
#include <utils/Log.h>


#include <cutils/sched_policy.h>

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <memory.h>
#include <memory.h>
@@ -269,6 +271,53 @@ void androidSetCreateThreadFunc(android_create_thread_fn func)
    gCreateThreadFn = func;
    gCreateThreadFn = func;
}
}


pid_t androidGetTid()
{
#ifdef HAVE_GETTID
    return gettid();
#else
    return getpid();
#endif
}

int androidSetThreadSchedulingGroup(pid_t tid, int grp)
{
    if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
        return BAD_VALUE;
    }

    if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
                                      SP_BACKGROUND : SP_FOREGROUND)) {
        return PERMISSION_DENIED;
    }
    
    return NO_ERROR;
}

int androidSetThreadPriority(pid_t tid, int pri)
{
    int rc = 0;
    int lasterr = 0;

    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
        rc = set_sched_policy(tid, SP_BACKGROUND);
    } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
        rc = set_sched_policy(tid, SP_FOREGROUND);
    }

    if (rc) {
        lasterr = errno;
    }

    if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
        rc = INVALID_OPERATION;
    } else {
        errno = lasterr;
    }
    
    return rc;
}

namespace android {
namespace android {


/*
/*