/******************************************************************************
*
* Copyright (C) 2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/************************************************************************************
*
* Filename: bt_utils.c
*
* Description: Miscellaneous helper functions
*
*
***********************************************************************************/
#define LOG_TAG "bt_utils"
#include "bt_utils.h"
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <unistd.h>
#include <utils/ThreadDefs.h>
#include <cutils/sched_policy.h>
#include "bt_types.h"
#include "btcore/include/module.h"
#include "osi/include/compat.h"
#include "osi/include/log.h"
#include "osi/include/properties.h"
/*******************************************************************************
** Type definitions for callback functions
********************************************************************************/
static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
static BOOLEAN g_DoSchedulingGroup[TASK_HIGH_MAX];
static pthread_mutex_t gIdxLock;
static int g_TaskIdx;
static int g_TaskIDs[TASK_HIGH_MAX];
#define INVALID_TASK_ID (-1)
static future_t *init(void) {
int i;
pthread_mutexattr_t lock_attr;
for(i = 0; i < TASK_HIGH_MAX; i++) {
g_DoSchedulingGroupOnce[i] = PTHREAD_ONCE_INIT;
g_DoSchedulingGroup[i] = TRUE;
g_TaskIDs[i] = INVALID_TASK_ID;
}
pthread_mutexattr_init(&lock_attr);
pthread_mutex_init(&gIdxLock, &lock_attr);
return NULL;
}
static future_t *clean_up(void) {
pthread_mutex_destroy(&gIdxLock);
return NULL;
}
EXPORT_SYMBOL const module_t bt_utils_module = {
.name = BT_UTILS_MODULE,
.init = init,
.start_up = NULL,
.shut_down = NULL,
.clean_up = clean_up,
.dependencies = {
NULL
}
};
/*****************************************************************************
**
** Function check_do_scheduling_group
**
** Description check if it is ok to change schedule group
**
** Returns void
**
*******************************************************************************/
static void check_do_scheduling_group(void) {
char buf[PROPERTY_VALUE_MAX];
int len = osi_property_get("debug.sys.noschedgroups", buf, "");
if (len > 0) {
int temp;
if (sscanf(buf, "%d", &temp) == 1) {
g_DoSchedulingGroup[g_TaskIdx] = temp == 0;
}
}
}
/*****************************************************************************
**
** Function raise_priority_a2dp
**
** Description Raise task priority for A2DP streaming
**
** Returns void
**
*******************************************************************************/
void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
int rc = 0;
int tid = gettid();
int priority = ANDROID_PRIORITY_AUDIO;
pthread_mutex_lock(&gIdxLock);
g_TaskIdx = high_task;
// TODO(armansito): Remove this conditional check once we find a solution
// for system/core on non-Android platforms.
#if defined(OS_GENERIC)
rc = -1;
#else // !defined(OS_GENERIC)
pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx], check_do_scheduling_group);
if (g_DoSchedulingGroup[g_TaskIdx]) {
// set_sched_policy does not support tid == 0
rc = set_sched_policy(tid, SP_AUDIO_SYS);
}
#endif // defined(OS_GENERIC)
g_TaskIDs[high_task] = tid;
pthread_mutex_unlock(&gIdxLock);
if (rc) {
LOG_WARN(LOG_TAG, "failed to change sched policy, tid %d, err: %d", tid, errno);
}
// always use urgent priority for HCI worker thread until we can adjust
// its prio individually. All other threads can be dynamically adjusted voa
// adjust_priority_a2dp()
priority = ANDROID_PRIORITY_URGENT_AUDIO;
if (setpriority(PRIO_PROCESS, tid, priority) < 0) {
LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
}
}
/*****************************************************************************
**
** Function adjust_priority_a2dp
**
** Description increase the a2dp consumer task priority temporarily when start
** audio playing, to avoid overflow the audio packet queue, restore
** the a2dp consumer task priority when stop audio playing.
**
** Returns void
**
*******************************************************************************/
void adjust_priority_a2dp(int start) {
int priority = start ? ANDROID_PRIORITY_URGENT_AUDIO : ANDROID_PRIORITY_AUDIO;
int tid;
int i;
for (i = 0; i < TASK_HIGH_MAX; i++)
{
tid = g_TaskIDs[i];
if (tid != INVALID_TASK_ID)
{
if (setpriority(PRIO_PROCESS, tid, priority) < 0)
{
LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
}
}
}
}