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 "bt_utils.h"
31 
32 #include <errno.h>
33 #include <pthread.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <sys/resource.h>
37 #include <unistd.h>
38 
39 #include <utils/ThreadDefs.h>
40 #include <cutils/sched_policy.h>
41 
42 #include "bt_types.h"
43 #include "btcore/include/module.h"
44 #include "osi/include/compat.h"
45 #include "osi/include/log.h"
46 #include "osi/include/properties.h"
47 
48 /*******************************************************************************
49 **  Type definitions for callback functions
50 ********************************************************************************/
51 static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
52 static BOOLEAN g_DoSchedulingGroup[TASK_HIGH_MAX];
53 static pthread_mutex_t         gIdxLock;
54 static int g_TaskIdx;
55 static int g_TaskIDs[TASK_HIGH_MAX];
56 #define INVALID_TASK_ID  (-1)
57 
init(void)58 static future_t *init(void) {
59   int i;
60   pthread_mutexattr_t lock_attr;
61 
62   for(i = 0; i < TASK_HIGH_MAX; i++) {
63     g_DoSchedulingGroupOnce[i] = PTHREAD_ONCE_INIT;
64     g_DoSchedulingGroup[i] = TRUE;
65     g_TaskIDs[i] = INVALID_TASK_ID;
66   }
67 
68   pthread_mutexattr_init(&lock_attr);
69   pthread_mutex_init(&gIdxLock, &lock_attr);
70   return NULL;
71 }
72 
clean_up(void)73 static future_t *clean_up(void) {
74   pthread_mutex_destroy(&gIdxLock);
75   return NULL;
76 }
77 
78 EXPORT_SYMBOL const module_t bt_utils_module = {
79   .name = BT_UTILS_MODULE,
80   .init = init,
81   .start_up = NULL,
82   .shut_down = NULL,
83   .clean_up = clean_up,
84   .dependencies = {
85     NULL
86   }
87 };
88 
89 /*****************************************************************************
90 **
91 ** Function        check_do_scheduling_group
92 **
93 ** Description     check if it is ok to change schedule group
94 **
95 ** Returns         void
96 **
97 *******************************************************************************/
check_do_scheduling_group(void)98 static void check_do_scheduling_group(void) {
99     char buf[PROPERTY_VALUE_MAX];
100     int len = osi_property_get("debug.sys.noschedgroups", buf, "");
101     if (len > 0) {
102         int temp;
103         if (sscanf(buf, "%d", &temp) == 1) {
104             g_DoSchedulingGroup[g_TaskIdx] = temp == 0;
105         }
106     }
107 }
108 
109 /*****************************************************************************
110 **
111 ** Function        raise_priority_a2dp
112 **
113 ** Description     Raise task priority for A2DP streaming
114 **
115 ** Returns         void
116 **
117 *******************************************************************************/
raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task)118 void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
119     int rc = 0;
120     int tid = gettid();
121     int priority = ANDROID_PRIORITY_AUDIO;
122 
123     pthread_mutex_lock(&gIdxLock);
124     g_TaskIdx = high_task;
125 
126     // TODO(armansito): Remove this conditional check once we find a solution
127     // for system/core on non-Android platforms.
128 #if defined(OS_GENERIC)
129     rc = -1;
130 #else  // !defined(OS_GENERIC)
131     pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx], check_do_scheduling_group);
132     if (g_DoSchedulingGroup[g_TaskIdx]) {
133         // set_sched_policy does not support tid == 0
134         rc = set_sched_policy(tid, SP_AUDIO_SYS);
135     }
136 #endif  // defined(OS_GENERIC)
137 
138     g_TaskIDs[high_task] = tid;
139     pthread_mutex_unlock(&gIdxLock);
140 
141     if (rc) {
142         LOG_WARN(LOG_TAG, "failed to change sched policy, tid %d, err: %d", tid, errno);
143     }
144 
145     // always use urgent priority for HCI worker thread until we can adjust
146     // its prio individually. All other threads can be dynamically adjusted voa
147     // adjust_priority_a2dp()
148 
149     priority = ANDROID_PRIORITY_URGENT_AUDIO;
150 
151     if (setpriority(PRIO_PROCESS, tid, priority) < 0) {
152         LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
153     }
154 }
155 
156 /*****************************************************************************
157 **
158 ** Function        adjust_priority_a2dp
159 **
160 ** Description     increase the a2dp consumer task priority temporarily when start
161 **                 audio playing, to avoid overflow the audio packet queue, restore
162 **                 the a2dp consumer task priority when stop audio playing.
163 **
164 ** Returns         void
165 **
166 *******************************************************************************/
adjust_priority_a2dp(int start)167 void adjust_priority_a2dp(int start) {
168     int priority = start ? ANDROID_PRIORITY_URGENT_AUDIO : ANDROID_PRIORITY_AUDIO;
169     int tid;
170     int i;
171 
172     for (i = 0; i < TASK_HIGH_MAX; i++)
173     {
174         tid = g_TaskIDs[i];
175         if (tid != INVALID_TASK_ID)
176         {
177             if (setpriority(PRIO_PROCESS, tid, priority) < 0)
178             {
179                 LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
180             }
181         }
182     }
183 }
184