1/******************************************************************************
2 *
3 *  Copyright (C) 2012 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19/************************************************************************************
20 *
21 *  Filename:      bt_utils.c
22 *
23 *  Description:   Miscellaneous helper functions
24 *
25 *
26 ***********************************************************************************/
27
28#define LOG_TAG "bt_utils"
29
30#include <cutils/properties.h>
31#include <cutils/sched_policy.h>
32#include <errno.h>
33#include <pthread.h>
34#include <sys/resource.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <utils/ThreadDefs.h>
39
40#include "bt_types.h"
41#include "bt_utils.h"
42#include "btcore/include/module.h"
43#include "osi/include/compat.h"
44#include "osi/include/log.h"
45
46/*******************************************************************************
47**  Type definitions for callback functions
48********************************************************************************/
49static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
50static BOOLEAN g_DoSchedulingGroup[TASK_HIGH_MAX];
51static pthread_mutex_t         gIdxLock;
52static int g_TaskIdx;
53static int g_TaskIDs[TASK_HIGH_MAX];
54#define INVALID_TASK_ID  (-1)
55
56static future_t *init(void) {
57  int i;
58  pthread_mutexattr_t lock_attr;
59
60  for(i = 0; i < TASK_HIGH_MAX; i++) {
61    g_DoSchedulingGroupOnce[i] = PTHREAD_ONCE_INIT;
62    g_DoSchedulingGroup[i] = TRUE;
63    g_TaskIDs[i] = INVALID_TASK_ID;
64  }
65
66  pthread_mutexattr_init(&lock_attr);
67  pthread_mutex_init(&gIdxLock, &lock_attr);
68  return NULL;
69}
70
71static future_t *clean_up(void) {
72  pthread_mutex_destroy(&gIdxLock);
73  return NULL;
74}
75
76const module_t bt_utils_module = {
77  .name = BT_UTILS_MODULE,
78  .init = init,
79  .start_up = NULL,
80  .shut_down = NULL,
81  .clean_up = clean_up,
82  .dependencies = {
83    NULL
84  }
85};
86
87
88/*****************************************************************************
89**
90** Function        check_do_scheduling_group
91**
92** Description     check if it is ok to change schedule group
93**
94** Returns         void
95**
96*******************************************************************************/
97static void check_do_scheduling_group(void) {
98    char buf[PROPERTY_VALUE_MAX];
99    int len = property_get("debug.sys.noschedgroups", buf, "");
100    if (len > 0) {
101        int temp;
102        if (sscanf(buf, "%d", &temp) == 1) {
103            g_DoSchedulingGroup[g_TaskIdx] = temp == 0;
104        }
105    }
106}
107
108/*****************************************************************************
109**
110** Function        raise_priority_a2dp
111**
112** Description     Raise task priority for A2DP streaming
113**
114** Returns         void
115**
116*******************************************************************************/
117void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
118    int rc = 0;
119    int tid = gettid();
120    int priority = ANDROID_PRIORITY_AUDIO;
121
122    pthread_mutex_lock(&gIdxLock);
123    g_TaskIdx = high_task;
124
125    pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx], check_do_scheduling_group);
126    if (g_DoSchedulingGroup[g_TaskIdx]) {
127        // set_sched_policy does not support tid == 0
128        rc = set_sched_policy(tid, SP_AUDIO_SYS);
129    }
130    g_TaskIDs[high_task] = tid;
131    pthread_mutex_unlock(&gIdxLock);
132
133    if (rc) {
134        LOG_WARN("failed to change sched policy, tid %d, err: %d", tid, errno);
135    }
136
137    // always use urgent priority for HCI worker thread until we can adjust
138    // its prio individually. All other threads can be dynamically adjusted voa
139    // adjust_priority_a2dp()
140
141    if (high_task == TASK_HIGH_HCI_WORKER)
142       priority = ANDROID_PRIORITY_URGENT_AUDIO;
143
144    if (setpriority(PRIO_PROCESS, tid, priority) < 0) {
145        LOG_WARN("failed to change priority tid: %d to %d", tid, priority);
146    }
147}
148
149/*****************************************************************************
150**
151** Function        adjust_priority_a2dp
152**
153** Description     increase the a2dp consumer task priority temporarily when start
154**                 audio playing, to avoid overflow the audio packet queue, restore
155**                 the a2dp consumer task priority when stop audio playing.
156**
157** Returns         void
158**
159*******************************************************************************/
160void adjust_priority_a2dp(int start) {
161    int priority = start ? ANDROID_PRIORITY_URGENT_AUDIO : ANDROID_PRIORITY_AUDIO;
162    int tid;
163    int i;
164
165    for (i = 0; i < TASK_HIGH_MAX; i++)
166    {
167        tid = g_TaskIDs[i];
168        if (tid != INVALID_TASK_ID)
169        {
170            if (setpriority(PRIO_PROCESS, tid, priority) < 0)
171            {
172                LOG_WARN("failed to change priority tid: %d to %d", tid, priority);
173            }
174        }
175    }
176}
177